Permalink
5745 lines (4870 sloc) 235 KB
/*
* Copyright (c) 2018 Confetti Interactive Inc.
*
* This file is part of The-Forge
* (see https://github.com/ConfettiFX/The-Forge).
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "../../../Middleware_3/Input/InputSystem.h"
#include "../../../Middleware_3/Input/InputMappings.h"
#include "../../../Common_3/ThirdParty/OpenSource/TinySTL/vector.h"
#include "../../../Common_3/ThirdParty/OpenSource/TinySTL/string.h"
#include "../../../Common_3/Renderer/IRenderer.h"
#include "../../../Common_3/Renderer/GpuProfiler.h"
#include "../../../Common_3/OS/Core/RingBuffer.h"
#include "../../../Common_3/OS/Image/Image.h"
#include "../../../Common_3/OS/Interfaces/ILogManager.h"
#include "../../../Common_3/OS/Interfaces/IFileSystem.h"
#include "../../../Common_3/OS/Interfaces/IThread.h"
#include "../../../Common_3/OS/Interfaces/ITimeManager.h"
#include "../../../Common_3/OS/Interfaces/ICameraController.h"
#include "../../../Common_3/OS/Interfaces/IApp.h"
#include "../../../Middleware_3/UI/AppUI.h"
#include "../../../Common_3/OS/Core/DebugRenderer.h"
#include "Geometry.h"
#include "../../../Common_3/OS/Interfaces/IMemoryManager.h"
#if defined(_DURANGO)
#define BEGINALLOCATION(X) esramBeginAllocation(pRenderer->pESRAMManager, X, esramGetCurrentOffset(pRenderer->pESRAMManager))
#define ENDALLOCATION(X) esramEndAllocation(pRenderer->pESRAMManager)
#define DIRECT3D12
#else
#define BEGINALLOCATION(X)
#define ENDALLOCATION(X)
#endif
#if !defined(METAL)
#define MSAASAMPLECOUNT 2
#else
#define MSAASAMPLECOUNT 1
#endif
File mFile;
FileSystem mFileSystem;
LogManager mLogManager;
HiresTimer gTimer;
#if defined(__linux__)
//_countof is MSVS macro, add define for Linux. a is expected to be static array type
#define _countof(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
#endif
#define SCENE_SCALE 1.0f
const char* pszBases[] =
{
"../../../src/", // FSR_BinShaders
"../../../src/", // FSR_SrcShaders
"../../../src/", // FSR_BinShaders_Common
"../../../src/", // FSR_SrcShaders_Common
"../../../../../Art/SanMiguel_3/Textures", // FSR_Textures
"../../../../../Art/SanMiguel_3/Meshes", // FSR_Meshes
"../../../Resources/", // FSR_Builtin_Fonts
"../../../src/", // FSR_GpuConfig
"", // FSR_Animation
"../../../Resources/", // FSR_OtherFiles
};
#ifdef _DURANGO
#include "../../../Xbox/CommonXBOXOne_3/Renderer/Direct3D12/Direct3D12X.h"
#endif
// Rendering modes
typedef enum RenderMode
{
RENDERMODE_VISBUFF = 0,
RENDERMODE_DEFERRED = 1,
RENDERMODE_COUNT = 2
} RenderMode;
enum
{
DEFERRED_RT_ALBEDO = 0,
DEFERRED_RT_NORMAL,
DEFERRED_RT_SPECULAR,
DEFERRED_RT_SIMULATION,
DEFERRED_RT_COUNT
};
typedef enum OutputMode
{
OUTPUT_MODE_SDR = 0,
OUTPUT_MODE_HDR10,
OUTPUT_MODE_COUNT
}OutputMode;
typedef enum LightingMode
{
LIGHTING_PHONG = 0,
LIGHTING_PBR = 1,
LIGHTINGMODE_COUNT = 2
} LightingMode;
struct RootConstantData
{
float4 lightColor;
uint lightingMode;
uint outputMode;
float4 CameraPlane; //x : near, y : far
};
RootConstantData gRootConstantDrawsceneData;
struct SCurveInfo
{
float C1;
float C2;
float C3;
float UseSCurve;
float ScurveSlope;
float ScurveScale;
float linearScale;
float pad0;
uint outputMode;
};
SCurveInfo gSCurveInfomation;
struct GodrayInfo
{
float exposure;
float decay;
float density;
float weight;
float2 lightPosInSS;
uint NUM_SAMPLES;
};
typedef enum CurveConversionMode
{
CurveConversion_LinearScale = 0,
CurveConversion_SCurve = 1
} CurveConversionMode;
enum DisplayColorRange
{
ColorRange_RGB = 0,
ColorRange_YCbCr422 = 1,
ColorRange_YCbCr444 = 2
};
enum DisplaySignalRange
{
Display_SIGNAL_RANGE_FULL = 0,
Display_SIGNAL_RANGE_NARROW = 1
};
enum DisplayColorSpace
{
ColorSpace_Rec709 = 0,
ColorSpace_Rec2020 = 1,
ColorSpace_P3D65 = 2
};
struct DisplayChromacities
{
float RedX;
float RedY;
float GreenX;
float GreenY;
float BlueX;
float BlueY;
float WhiteX;
float WhiteY;
};
static const DisplayChromacities DisplayChromacityList[] =
{
{ 0.64000f, 0.33000f, 0.30000f, 0.60000f, 0.15000f, 0.06000f, 0.31270f, 0.32900f }, // Display Gamut Rec709
{ 0.70800f, 0.29200f, 0.17000f, 0.79700f, 0.13100f, 0.04600f, 0.31270f, 0.32900f }, // Display Gamut Rec2020
{ 0.68000f, 0.32000f, 0.26500f, 0.69000f, 0.15000f, 0.06000f, 0.31270f, 0.32900f }, // Display Gamut P3D65
{ 0.68000f, 0.32000f, 0.26500f, 0.69000f, 0.15000f, 0.06000f, 0.31400f, 0.35100f }, // Display Gamut P3DCI(Theater)
{ 0.68000f, 0.32000f, 0.26500f, 0.69000f, 0.15000f, 0.06000f, 0.32168f, 0.33767f }, // Display Gamut P3D60(ACES Cinema)
};
//Camera Walking
static int currentCameraFrame = 0;
static float cameraWalkingTime = 0.0f;
tinystl::vector<float3> positions_directions;
float3 CameraPathData[29084];
uint cameraPoints;
float totalElpasedTime;
typedef struct VisBufferIndirectCommand
{
// Metal does not use index buffer since there is no builtin primitive id
#if defined(METAL)
IndirectDrawArguments arg;
#else
// Draw ID is sent as indirect argument through root constant in DX12
#if defined(DIRECT3D12)
uint32_t drawId;
#endif
IndirectDrawIndexArguments arg;
#if defined(DIRECT3D12)
uint32_t _pad0, _pad1;
#else
uint32_t _pad0, _pad1, _pad2;
#endif
#endif
} VisBufferIndirectCommand;
#if defined(METAL)
// Constant data updated for every batch
struct PerBatchConstants
{
uint32_t drawId; // used to idendify the batch from the shader
uint32_t twoSided; // possible values: 0/1
};
#endif
/************************************************************************/
// GUI CONTROLS
/************************************************************************/
typedef struct AppSettings
{
OutputMode mOutputMode = OUTPUT_MODE_SDR;
// Current active rendering mode
RenderMode mRenderMode = RENDERMODE_VISBUFF;
LightingMode mLightingMode = LIGHTING_PBR;
// Set this variable to true to bypass triangle filtering calculations, holding and representing the last filtered data.
// This is useful for inspecting filtered geometry for debugging purposes.
bool mHoldFilteredResults = false;
// This variable enables or disables triangle filtering. When filtering is disabled, all the scene is rendered unconditionally.
bool mFilterTriangles = true;
// Turns off cluster culling by default
// Cluster culling increases CPU time and does not provide enough benefit in terms of culling results to keep it enabled by default
bool mClusterCulling = false;
bool mAsyncCompute = true;
// toggle rendering of local point lights
bool mRenderLocalLights = false;
#if MSAASAMPLECOUNT == 1
bool mDrawDebugTargets = false;
#else
bool mDrawDebugTargets = false;
#endif
float nearPlane = 10.0f;
float farPlane = 3000.0f;
// adjust directional sunlight angle
float2 mSunControl = { -2.1f, 0.164f };
float mSunSize = 300.0f;
float4 mLightColor = { 1.0f, 0.8627f, 0.78f, 2.5f };
DynamicUIControls mDynamicUIControlsGR;
GodrayInfo gGodrayInfo;
bool mEnableGodray = true;
uint gGodrayInteration = 3;
float mEsmControl = 80.0f;
float mRetinaScaling = 1.5f;
// HDAO data
DynamicUIControls mDynamicUIControlsAO;
bool mEnableHDAO = true;
float mRejectRadius = 5.2f;
float mAcceptRadius = 0.12f;
float mAOIntensity = 3.0f;
int mAOQuality = 2;
DynamicUIControls mSCurve;
float SCurveScaleFactor = 1.0f;
float SCurveSMin = 0.00f;
float SCurveSMid = 0.84f;
float SCurveSMax = 65.65f;
float SCurveTMin = 0.0f;
float SCurveTMid = 139.76f;
float SCurveTMax = 1100.0f;
float SCurveSlopeFactor = 2.2f;
DynamicUIControls mLinearScale;
float LinearScale = 140.0f;
// HDR10
DynamicUIControls mDisplaySetting;
DisplayColorSpace mCurrentSwapChainColorSpace = ColorSpace_Rec2020;
DisplayColorRange mDisplayColorRange = ColorRange_RGB;
DisplaySignalRange mDisplaySignalRange = Display_SIGNAL_RANGE_FULL;
CurveConversionMode mCurveConversionMode = CurveConversion_SCurve;
float MaxOutputNits = 1000.0f;
float MinOutputNits = 0.03f;
float MaxCLL = 1000.0f;
float MaxFALL = 20.0f;
//Camera Walking
bool cameraWalking = false;
float cameraWalkingSpeed = 1.0f;
} AppSettings;
/************************************************************************/
// Constants
/************************************************************************/
const char* gSceneName = "SanMiguel.obj";
const char* gSunName = "sun.obj";
// Number of in-flight buffers
const uint32_t gImageCount = 3;
uint32_t gPresentFrameIdx = ~0u;
bool gToggleVSync = false;
// Constants
const uint32_t gShadowMapSize = 1024;
const uint32_t gNumViews = NUM_CULLING_VIEWPORTS;
struct UniformDataSkybox
{
mat4 mProjectView;
vec3 mCamPos;
};
UniformDataSkybox gUniformDataSky;
const uint32_t gSkyboxSize = 1024;
const uint32_t gSkyboxMips = 9;
struct UniformDataSunMatrices
{
mat4 mProjectView;
mat4 mModelMat;
vec4 mLightColor;
};
mat4 SunMVP;
mat4 SunModel;
UniformDataSunMatrices gUniformDataSunMatrices;
int gGodrayScale = 8;
// Define different geometry sets (opaque and alpha tested geometry)
const uint32_t gNumGeomSets = 2;
const uint32_t GEOMSET_OPAQUE = 0;
const uint32_t GEOMSET_ALPHATESTED = 1;
// Memory budget used for internal ring buffer
const uint32_t gMemoryBudget = 1024ULL * 1024ULL * 64ULL;
/************************************************************************/
// Per frame staging data
/************************************************************************/
struct PerFrameData
{
// Stores the camera/eye position in object space for cluster culling
vec3 gEyeObjectSpace[NUM_CULLING_VIEWPORTS] = {};
PerFrameConstants gPerFrameUniformData = {};
// These are just used for statistical information
uint32_t gTotalClusters = 0;
uint32_t gCulledClusters = 0;
uint32_t gDrawCount[gNumGeomSets];
};
/************************************************************************/
// Settings
/************************************************************************/
AppSettings gAppSettings;
/************************************************************************/
// Rendering data
/************************************************************************/
Renderer* pRenderer = nullptr;
/************************************************************************/
// Synchronization primitives
/************************************************************************/
Fence* pTransitionFences = nullptr;
Fence* pRenderCompleteFences[gImageCount] = { nullptr };
Fence* pComputeCompleteFences[gImageCount] = { nullptr };
Semaphore* pImageAcquiredSemaphore = nullptr;
Semaphore* pRenderCompleteSemaphores[gImageCount] = { nullptr };
Semaphore* pComputeCompleteSemaphores[gImageCount] = { nullptr };
/************************************************************************/
// Queues and Command buffers
/************************************************************************/
Queue* pGraphicsQueue = nullptr;
CmdPool* pCmdPool = nullptr;
Cmd** ppCmds = nullptr;
Queue* pComputeQueue = nullptr;
CmdPool* pComputeCmdPool = nullptr;
Cmd** ppComputeCmds = nullptr;
/************************************************************************/
// Swapchain
/************************************************************************/
SwapChain* pSwapChain = nullptr;
/************************************************************************/
// Clear buffers pipeline
/************************************************************************/
Shader* pShaderClearBuffers = nullptr;
Pipeline* pPipelineClearBuffers = nullptr;
RootSignature* pRootSignatureClearBuffers = nullptr;
/************************************************************************/
// Triangle filtering pipeline
/************************************************************************/
Shader* pShaderTriangleFiltering = nullptr;
Pipeline* pPipelineTriangleFiltering = nullptr;
RootSignature* pRootSignatureTriangleFiltering = nullptr;
/************************************************************************/
// Batch compaction pipeline
/************************************************************************/
#if !defined(METAL)
Shader* pShaderBatchCompaction = nullptr;
Pipeline* pPipelineBatchCompaction = nullptr;
RootSignature* pRootSignatureBatchCompaction = nullptr;
#endif
/************************************************************************/
// Clear light clusters pipeline
/************************************************************************/
Shader* pShaderClearLightClusters = nullptr;
Pipeline* pPipelineClearLightClusters = nullptr;
RootSignature* pRootSignatureClearLightClusters = nullptr;
/************************************************************************/
// Compute light clusters pipeline
/************************************************************************/
Shader* pShaderClusterLights = nullptr;
Pipeline* pPipelineClusterLights = nullptr;
RootSignature* pRootSignatureClusterLights = nullptr;
/************************************************************************/
// Shadow pass pipeline
/************************************************************************/
Shader* pShaderShadowPass[gNumGeomSets] = { nullptr };
Pipeline* pPipelineShadowPass[gNumGeomSets] = { nullptr };
/************************************************************************/
// VB pass pipeline
/************************************************************************/
Shader* pShaderVisibilityBufferPass[gNumGeomSets] = {};
Pipeline* pPipelineVisibilityBufferPass[gNumGeomSets] = {};
RootSignature* pRootSignatureVBPass = nullptr;
CommandSignature* pCmdSignatureVBPass = nullptr;
/************************************************************************/
// VB shade pipeline
/************************************************************************/
Shader* pShaderVisibilityBufferShade[2] = { nullptr };
Pipeline* pPipelineVisibilityBufferShadeSrgb[2] = { nullptr };
RootSignature* pRootSignatureVBShade = nullptr;
/************************************************************************/
// Deferred pass pipeline
/************************************************************************/
Shader* pShaderDeferredPass[gNumGeomSets] = {};
Pipeline* pPipelineDeferredPass[gNumGeomSets] = {};
RootSignature* pRootSignatureDeferredPass = nullptr;
CommandSignature* pCmdSignatureDeferredPass = nullptr;
/************************************************************************/
// Deferred shade pipeline
/************************************************************************/
Shader* pShaderDeferredShade[2] = { nullptr };
Pipeline* pPipelineDeferredShadeSrgb[2] = { nullptr };
RootSignature* pRootSignatureDeferredShade = nullptr;
/************************************************************************/
// Deferred point light shade pipeline
/************************************************************************/
Shader* pShaderDeferredShadePointLight = nullptr;
Pipeline* pPipelineDeferredShadePointLightSrgb = nullptr;
RootSignature* pRootSignatureDeferredShadePointLight = nullptr;
/************************************************************************/
// AO pipeline
/************************************************************************/
Shader* pShaderAO[4] = { nullptr };
Pipeline* pPipelineAO[4] = { nullptr };
RootSignature* pRootSignatureAO = nullptr;
/************************************************************************/
// Resolve pipeline
/************************************************************************/
Shader* pShaderResolve = nullptr;
Pipeline* pPipelineResolve = nullptr;
Pipeline* pPipelineResolvePost = nullptr;
RootSignature* pRootSignatureResolve = nullptr;
Shader* pShaderGodrayResolve = nullptr;
Pipeline* pPipelineGodrayResolve = nullptr;
Pipeline* pPipelineGodrayResolvePost = nullptr;
RootSignature* pRootSignatureGodrayResolve = nullptr;
/************************************************************************/
// Skybox pipeline
/************************************************************************/
Shader* pShaderSkybox = nullptr;
Pipeline* pSkyboxPipeline = nullptr;
RootSignature* pRootSingatureSkybox = nullptr;
Buffer* pSkyboxVertexBuffer = NULL;
Texture* pSkybox = NULL;
/************************************************************************/
// Godray pipeline
/************************************************************************/
Shader* pSunPass = nullptr;
Pipeline* pPipelineSunPass = nullptr;
RootSignature* pRootSigSunPass = nullptr;
Shader* pGodRayPass = nullptr;
Pipeline* pPipelineGodRayPass = nullptr;
RootSignature* pRootSigGodRayPass = nullptr;
uint SunVertexCount;
uint SunIndexCount;
Buffer* pSunVertexBuffer = NULL;
Buffer* pSunIndexBuffer = NULL;
/************************************************************************/
// Curve Conversion pipeline
/************************************************************************/
Shader* pShaderCurveConversion = nullptr;
Pipeline* pPipelineCurveConversionPass = nullptr;
RootSignature* pRootSigCurveConversionPass = nullptr;
OutputMode gWasOutputMode = gAppSettings.mOutputMode;
DisplayColorSpace gWasColorSpace = gAppSettings.mCurrentSwapChainColorSpace;
DisplayColorRange gWasDisplayColorRange = gAppSettings.mDisplayColorRange;
DisplaySignalRange gWasDisplaySignalRange = gAppSettings.mDisplaySignalRange;
/************************************************************************/
// Present pipeline
/************************************************************************/
Shader* pShaderPresentPass = nullptr;
Pipeline* pPipelinePresentPass = nullptr;
RootSignature* pRootSigPresentPass = nullptr;
/************************************************************************/
// Render targets
/************************************************************************/
RenderTarget* pDepthBuffer = nullptr;
RenderTarget* pRenderTargetVBPass = nullptr;
RenderTarget* pRenderTargetMSAA = nullptr;
RenderTarget* pRenderTargetDeferredPass[DEFERRED_RT_COUNT] = { nullptr };
RenderTarget* pRenderTargetShadow = nullptr;
RenderTarget* pRenderTargetAO = nullptr;
RenderTarget* pIntermediateRenderTarget = nullptr;
RenderTarget* pRenderTargetSun = nullptr;
RenderTarget* pRenderTargetSunResolved = nullptr;
RenderTarget* pRenderTargetGodRayA = nullptr;
RenderTarget* pRenderTargetGodRayB = nullptr;
RenderTarget* pCurveConversionRenderTarget = nullptr;
/************************************************************************/
// Rasterizer states
/************************************************************************/
RasterizerState* pRasterizerStateCullBack = nullptr;
RasterizerState* pRasterizerStateCullFront = nullptr;
RasterizerState* pRasterizerStateCullNone = nullptr;
RasterizerState* pRasterizerStateCullBackMS = nullptr;
RasterizerState* pRasterizerStateCullFrontMS = nullptr;
RasterizerState* pRasterizerStateCullNoneMS = nullptr;
/************************************************************************/
// Depth states
/************************************************************************/
DepthState* pDepthStateEnable = nullptr;
DepthState* pDepthStateDisable = nullptr;
/************************************************************************/
// Blend state used in deferred point light shading
/************************************************************************/
BlendState* pBlendStateOneZero = nullptr;
BlendState* pBlendStateSkyBox = nullptr;
/************************************************************************/
// Samplers
/************************************************************************/
Sampler* pSamplerTrilinearAniso = nullptr;
Sampler* pSamplerBilinear = nullptr;
Sampler* pSamplerPointClamp = nullptr;
Sampler* pSamplerBilinearClamp = nullptr;
/************************************************************************/
// Bindless texture array
/************************************************************************/
Texture* gDiffuseMapsStorage = NULL;
Texture* gNormalMapsStorage = NULL;
Texture* gSpecularMapsStorage = NULL;
tinystl::vector<Texture*> gDiffuseMaps;
tinystl::vector<Texture*> gNormalMaps;
tinystl::vector<Texture*> gSpecularMaps;
tinystl::vector<Texture*> gDiffuseMapsPacked;
tinystl::vector<Texture*> gNormalMapsPacked;
tinystl::vector<Texture*> gSpecularMapsPacked;
/************************************************************************/
// Vertex buffers for the scene
/************************************************************************/
Buffer* pVertexBufferPosition = nullptr;
Buffer* pVertexBufferTexCoord = nullptr;
Buffer* pVertexBufferNormal = nullptr;
Buffer* pVertexBufferTangent = nullptr;
/************************************************************************/
// Indirect buffers
/************************************************************************/
Buffer* pMaterialPropertyBuffer = nullptr;
Buffer* pPerFrameUniformBuffers[gImageCount] = { nullptr };
#if defined(METAL)
// Buffer containing all indirect draw commands for all geometry sets (no culling)
Buffer* pIndirectDrawArgumentsBufferAll = nullptr;
Buffer* pIndirectMaterialBufferAll = nullptr;
// Buffer containing filtered indirect draw commands for all geometry sets (culled)
Buffer* pFilteredIndirectDrawArgumentsBuffer[gImageCount][gNumViews] = {};
#else
// Buffers containing all indirect draw commands per geometry set (no culling)
Buffer* pIndirectDrawArgumentsBufferAll[gNumGeomSets] = { nullptr };
Buffer* pIndirectMaterialBufferAll = nullptr;
Buffer* pMeshConstantsBuffer = nullptr;
// Buffers containing filtered indirect draw commands per geometry set (culled)
Buffer* pFilteredIndirectDrawArgumentsBuffer[gImageCount][gNumGeomSets][gNumViews] = { nullptr };
// Buffer containing the draw args after triangle culling which will be stored compactly in the indirect buffer
Buffer* pUncompactedDrawArgumentsBuffer[gImageCount][gNumViews] = { nullptr };
Buffer* pFilterIndirectMaterialBuffer[gImageCount] = { nullptr };
#endif
/************************************************************************/
// Index buffers
/************************************************************************/
Buffer* pIndexBufferAll = nullptr;
Buffer* pFilteredIndexBuffer[gImageCount][gNumViews] = {};
/************************************************************************/
// Other buffers for lighting, point lights,...
/************************************************************************/
Buffer* pLightsBuffer = nullptr;
Buffer** gPerBatchUniformBuffers = nullptr;
Buffer* pVertexBufferCube = nullptr;
Buffer* pIndexBufferCube = nullptr;
Buffer* pLightClustersCount[gImageCount] = { nullptr };
Buffer* pLightClusters[gImageCount] = { nullptr };
uint64_t gFrameCount = 0;
Scene* pScene = nullptr;
UIApp gAppUI;
GuiComponent* pGuiWindow = nullptr;
TextDrawDesc gFrameTimeDraw = TextDrawDesc(0, 0xff00ffff, 18);
/************************************************************************/
// Triangle filtering data
/************************************************************************/
#if defined(METAL)
FilterBatchChunk* pFilterBatchChunk[gImageCount] = { nullptr };
#else
const uint32_t gSmallBatchChunkCount = max(1U, 512U / CLUSTER_SIZE) * 16U;
FilterBatchChunk* pFilterBatchChunk[gImageCount][gSmallBatchChunkCount] = { nullptr };
UniformRingBuffer* pFilterBatchDataBuffer[gImageCount] = { nullptr };
#endif
/************************************************************************/
// GPU Profilers
/************************************************************************/
GpuProfiler* pGraphicsGpuProfiler = nullptr;
GpuProfiler* pComputeGpuProfiler = nullptr;
ICameraController* pCameraController = nullptr;
/************************************************************************/
// CPU staging data
/************************************************************************/
// CPU buffers for light data
LightData gLightData[LIGHT_COUNT] = {};
PerFrameData gPerFrame[gImageCount] = {};
RenderTarget* pScreenRenderTarget = nullptr;
/************************************************************************/
// Screen resolution UI data
/************************************************************************/
#if !defined(_DURANGO) && !defined(METAL) && !defined(__linux__)
IWidget* gResolutionProperty = nullptr;
tinystl::vector<Resolution> gResolutions;
uint32_t gResolutionIndex = 0;
bool gResolutionChange = false;
#endif
/************************************************************************/
/************************************************************************/
class VisibilityBuffer* pVisibilityBuffer = nullptr;
/************************************************************************/
// Culling intrinsic data
/************************************************************************/
const uint32_t pdep_lut[8] = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15 };
/************************************************************************/
// App implementation
/************************************************************************/
IWidget* addResolutionProperty(GuiComponent* pUIManager, uint32_t& resolutionIndex, uint32_t resCount, Resolution* pResolutions, WidgetCallback onResolutionChanged)
{
#if !defined(_DURANGO) && !defined(METAL) && !defined(__linux__)
if (pUIManager)
{
struct ResolutionData
{
tinystl::vector<tinystl::string> resNameContainer;
tinystl::vector<const char*> resNamePointers;
tinystl::vector<uint32_t> resValues;
};
static tinystl::unordered_map<GuiComponent*, ResolutionData> guiResolution;
ResolutionData& data = guiResolution[pUIManager];
data.resNameContainer.clear();
data.resNamePointers.clear();
data.resValues.clear();
for (uint32_t i = 0; i < resCount; ++i)
{
data.resNameContainer.push_back(tinystl::string::format("%ux%u", pResolutions[i].mWidth, pResolutions[i].mHeight));
data.resValues.push_back(i);
}
data.resNamePointers.resize(data.resNameContainer.size() + 1);
for (uint32_t i = 0; i < (uint32_t)data.resNameContainer.size(); ++i)
{
data.resNamePointers[i] = data.resNameContainer[i];
}
data.resNamePointers[data.resNamePointers.size() - 1] = nullptr;
DropdownWidget control("Screen Resolution", &resolutionIndex, data.resNamePointers.data(), data.resValues.data(), (uint32_t)data.resValues.size());
control.pOnEdited = onResolutionChanged;
return pUIManager->AddWidget(control);
}
#endif
return NULL;
}
class VisibilityBuffer : public IApp
{
public:
#if defined(DIRECT3D12)
void SetHDRMetaData(float MaxOutputNits, float MinOutputNits, float MaxCLL, float MaxFALL)
{
#if !defined(_DURANGO)
// Clean the hdr metadata if the display doesn't support HDR
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
if (gAppSettings.mCurrentSwapChainColorSpace == ColorSpace_Rec2020)
{
colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
}
else if (gAppSettings.mCurrentSwapChainColorSpace == ColorSpace_P3D65)
{
}
UINT colorSpaceSupport = 0;
if (SUCCEEDED(pSwapChain->pDxSwapChain->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport)) &&
((colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) == DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
{
pSwapChain->pDxSwapChain->SetColorSpace1(colorSpace);
}
#endif
}
#endif
bool Init()
{
// Overwrite rootpath is required because Textures and meshes are not in /Textures and /Meshes.
// We need to set the modified root path so that filesystem can find the meshes and textures.
FileSystem::SetRootPath(FSRoot::FSR_Meshes, "/");
FileSystem::SetRootPath(FSRoot::FSR_Textures, "/");
pVisibilityBuffer = this;
/************************************************************************/
// Initialize the Forge renderer with the appropriate parameters.
/************************************************************************/
RendererDesc settings = {};
initRenderer(GetName(), &settings, &pRenderer);
//check for init success
if (!pRenderer)
return false;
//Camera Walking
tinystl::string fn("cameraPath.bin");
mFile.Open(fn, FM_ReadBinary, FSR_OtherFiles);
mFile.Read(CameraPathData, sizeof(float3) * 29084);
mFile.Close();
cameraPoints = (uint)29084 / 2;
totalElpasedTime = (float)cameraPoints * 0.00833f;
QueueDesc queueDesc = {};
queueDesc.mType = CMD_POOL_DIRECT;
addQueue(pRenderer, &queueDesc, &pGraphicsQueue);
// Create the command pool and the command lists used to store GPU commands.
// One Cmd list per back buffer image is stored for triple buffering.
addCmdPool(pRenderer, pGraphicsQueue, false, &pCmdPool);
addCmd_n(pCmdPool, false, gImageCount, &ppCmds);
QueueDesc computeQueueDesc = {};
computeQueueDesc.mType = CMD_POOL_COMPUTE;
addQueue(pRenderer, &computeQueueDesc, &pComputeQueue);
// Create the command pool and the command lists used to store GPU commands.
// One Cmd list per back buffer image is stored for triple buffering.
addCmdPool(pRenderer, pComputeQueue, false, &pComputeCmdPool);
addCmd_n(pComputeCmdPool, false, gImageCount, &ppComputeCmds);
addFence(pRenderer, &pTransitionFences);
addSemaphore(pRenderer, &pImageAcquiredSemaphore);
/************************************************************************/
// Initialize helper interfaces (resource loader, profiler)
/************************************************************************/
initResourceLoaderInterface(pRenderer, gMemoryBudget);
initDebugRendererInterface(pRenderer, "TitilliumText/TitilliumText-Bold.otf", FSR_Builtin_Fonts);
addGpuProfiler(pRenderer, pGraphicsQueue, &pGraphicsGpuProfiler);
addGpuProfiler(pRenderer, pComputeQueue, &pComputeGpuProfiler);
/************************************************************************/
// Start timing the scene load
/************************************************************************/
HiresTimer timer;
HiresTimer shaderTimer;
// Load shaders
addShaders();
LOGINFOF("Load shaders : %f ms", shaderTimer.GetUSec(true) / 1000.0f);
/************************************************************************/
// Setup default depth, blend, rasterizer, sampler states
/************************************************************************/
DepthStateDesc depthStateDesc = {};
depthStateDesc.mDepthTest = true;
depthStateDesc.mDepthWrite = true;
depthStateDesc.mDepthFunc = CMP_LEQUAL;
DepthStateDesc depthStateDisableDesc = {};
addDepthState(pRenderer, &depthStateDesc, &pDepthStateEnable);
addDepthState(pRenderer, &depthStateDisableDesc, &pDepthStateDisable);
RasterizerStateDesc rasterizerStateCullFrontDesc = { CULL_MODE_FRONT };
RasterizerStateDesc rasterizerStateCullNoneDesc = { CULL_MODE_NONE };
RasterizerStateDesc rasterizerStateCullBackDesc = { CULL_MODE_BACK };
RasterizerStateDesc rasterizerStateCullFrontMsDesc = { CULL_MODE_FRONT, 0, 0, FILL_MODE_SOLID, true };
RasterizerStateDesc rasterizerStateCullNoneMsDesc = { CULL_MODE_NONE, 0, 0, FILL_MODE_SOLID, true };
RasterizerStateDesc rasterizerStateCullBackMsDesc = { CULL_MODE_BACK, 0, 0, FILL_MODE_SOLID, true };
addRasterizerState(pRenderer, &rasterizerStateCullFrontDesc, &pRasterizerStateCullFront);
addRasterizerState(pRenderer, &rasterizerStateCullNoneDesc, &pRasterizerStateCullNone);
addRasterizerState(pRenderer, &rasterizerStateCullBackDesc, &pRasterizerStateCullBack);
addRasterizerState(pRenderer, &rasterizerStateCullFrontMsDesc, &pRasterizerStateCullFrontMS);
addRasterizerState(pRenderer, &rasterizerStateCullNoneMsDesc, &pRasterizerStateCullNoneMS);
addRasterizerState(pRenderer, &rasterizerStateCullBackMsDesc, &pRasterizerStateCullBackMS);
BlendStateDesc blendStateDesc = {};
blendStateDesc.mSrcAlphaFactors[0] = BC_ONE;
blendStateDesc.mDstAlphaFactors[0] = BC_ZERO;
blendStateDesc.mSrcFactors[0] = BC_ONE;
blendStateDesc.mDstFactors[0] = BC_ONE;
blendStateDesc.mMasks[0] = ALL;
blendStateDesc.mRenderTargetMask = BLEND_STATE_TARGET_0;
blendStateDesc.mIndependentBlend = false;
addBlendState(pRenderer, &blendStateDesc, &pBlendStateOneZero);
BlendStateDesc blendStateSkyBoxDesc = {};
blendStateSkyBoxDesc.mBlendModes[0] = BM_ADD;
blendStateSkyBoxDesc.mBlendAlphaModes[0] = BM_ADD;
blendStateSkyBoxDesc.mSrcFactors[0] = BC_ONE_MINUS_DST_ALPHA;
blendStateSkyBoxDesc.mDstFactors[0] = BC_DST_ALPHA;
blendStateSkyBoxDesc.mSrcAlphaFactors[0] = BC_ZERO;
blendStateSkyBoxDesc.mDstAlphaFactors[0] = BC_ONE;
blendStateSkyBoxDesc.mMasks[0] = ALL;
blendStateSkyBoxDesc.mRenderTargetMask = BLEND_STATE_TARGET_0;
blendStateDesc.mIndependentBlend = false;
addBlendState(pRenderer, &blendStateSkyBoxDesc, &pBlendStateSkyBox);
// Create sampler for VB render target
SamplerDesc trilinearDesc = {
FILTER_LINEAR, FILTER_LINEAR, MIPMAP_MODE_LINEAR,
ADDRESS_MODE_REPEAT, ADDRESS_MODE_REPEAT, ADDRESS_MODE_REPEAT, 0.0f, 8.0f
};
SamplerDesc bilinearDesc = {
FILTER_LINEAR, FILTER_LINEAR, MIPMAP_MODE_LINEAR,
ADDRESS_MODE_REPEAT, ADDRESS_MODE_REPEAT, ADDRESS_MODE_REPEAT
};
SamplerDesc pointDesc = {
FILTER_NEAREST, FILTER_NEAREST, MIPMAP_MODE_NEAREST,
ADDRESS_MODE_CLAMP_TO_EDGE, ADDRESS_MODE_CLAMP_TO_EDGE, ADDRESS_MODE_CLAMP_TO_EDGE
};
SamplerDesc bilinearClampDesc = {
FILTER_LINEAR, FILTER_LINEAR, MIPMAP_MODE_LINEAR,
ADDRESS_MODE_CLAMP_TO_EDGE, ADDRESS_MODE_CLAMP_TO_EDGE, ADDRESS_MODE_CLAMP_TO_EDGE
};
addSampler(pRenderer, &trilinearDesc, &pSamplerTrilinearAniso);
addSampler(pRenderer, &bilinearDesc, &pSamplerBilinear);
addSampler(pRenderer, &pointDesc, &pSamplerPointClamp);
addSampler(pRenderer, &bilinearClampDesc, &pSamplerBilinearClamp);
/************************************************************************/
// Load resources for skybox
/************************************************************************/
LoadSkybox();
/************************************************************************/
// Load the scene using the SceneLoader class, which uses Assimp
/************************************************************************/
HiresTimer sceneLoadTimer;
tinystl::string sceneFullPath = FileSystem::FixPath(gSceneName, FSRoot::FSR_Meshes);
pScene = loadScene(sceneFullPath.c_str(), 50.0f, -20.0f, 0.0f, 0.0f);
if (!pScene)
return false;
LOGINFOF("Load assimp scene : %f ms", sceneLoadTimer.GetUSec(true) / 1000.0f);
/************************************************************************/
// IA buffers
/************************************************************************/
HiresTimer bufferLoadTimer;
#if !defined(METAL)
// Default (non-filtered) index buffer for the scene
BufferLoadDesc ibDesc = {};
ibDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_INDEX_BUFFER | DESCRIPTOR_TYPE_BUFFER;
ibDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
ibDesc.mDesc.mIndexType = INDEX_TYPE_UINT32;
ibDesc.mDesc.mElementCount = pScene->totalTriangles * 3;
ibDesc.mDesc.mStructStride = sizeof(uint32_t);
ibDesc.mDesc.mSize = ibDesc.mDesc.mElementCount * ibDesc.mDesc.mStructStride;
ibDesc.pData = pScene->indices.data();
ibDesc.ppBuffer = &pIndexBufferAll;
ibDesc.mDesc.pDebugName = L"Non-filtered Index Buffer Desc";
addResource(&ibDesc);
#else
// Fill the pIndexBufferAll with triangle IDs for the whole scene (since metal implementation doesn't use scene indices).
uint32_t* trianglesBuffer = (uint32_t*)conf_malloc(pScene->totalTriangles * 3 * sizeof(uint32_t));
for (uint32_t i = 0, t = 0; i<pScene->numMeshes; i++)
{
for (uint32_t j = 0; j<pScene->meshes[i].triangleCount; j++, t++)
trianglesBuffer[t] = j;
}
BufferLoadDesc ibDesc = {};
ibDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_INDEX_BUFFER | DESCRIPTOR_TYPE_BUFFER;
ibDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
ibDesc.mDesc.mIndexType = INDEX_TYPE_UINT32;
ibDesc.mDesc.mElementCount = pScene->totalTriangles * 3;
ibDesc.mDesc.mStructStride = sizeof(uint32_t);
ibDesc.mDesc.mSize = ibDesc.mDesc.mElementCount * ibDesc.mDesc.mStructStride;
ibDesc.pData = trianglesBuffer;
ibDesc.ppBuffer = &pIndexBufferAll;
ibDesc.mDesc.pDebugName = L"Non-filtered Index Buffer Desc";
addResource(&ibDesc);
conf_free(trianglesBuffer);
#endif
// Vertex position buffer for the scene
BufferLoadDesc vbPosDesc = {};
vbPosDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_VERTEX_BUFFER | DESCRIPTOR_TYPE_BUFFER;
vbPosDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
vbPosDesc.mDesc.mVertexStride = sizeof(SceneVertexPos);
vbPosDesc.mDesc.mElementCount = pScene->totalVertices;
vbPosDesc.mDesc.mStructStride = sizeof(SceneVertexPos);
vbPosDesc.mDesc.mSize = vbPosDesc.mDesc.mElementCount * vbPosDesc.mDesc.mStructStride;
vbPosDesc.pData = pScene->positions.data();
vbPosDesc.ppBuffer = &pVertexBufferPosition;
vbPosDesc.mDesc.pDebugName = L"Vertex Position Buffer Desc";
addResource(&vbPosDesc);
// Vertex texcoord buffer for the scene
BufferLoadDesc vbTexCoordDesc = {};
vbTexCoordDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_VERTEX_BUFFER | DESCRIPTOR_TYPE_BUFFER;
vbTexCoordDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
vbTexCoordDesc.mDesc.mVertexStride = sizeof(SceneVertexTexCoord);
vbTexCoordDesc.mDesc.mElementCount = pScene->totalVertices * (sizeof(SceneVertexTexCoord) / sizeof(uint32_t));
vbTexCoordDesc.mDesc.mStructStride = sizeof(uint32_t);
vbTexCoordDesc.mDesc.mSize = vbTexCoordDesc.mDesc.mElementCount * vbTexCoordDesc.mDesc.mStructStride;
vbTexCoordDesc.pData = pScene->texCoords.data();
vbTexCoordDesc.ppBuffer = &pVertexBufferTexCoord;
vbTexCoordDesc.mDesc.pDebugName = L"Vertex TexCoord Buffer Desc";
addResource(&vbTexCoordDesc);
// Vertex normal buffer for the scene
BufferLoadDesc vbNormalDesc = {};
vbNormalDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_VERTEX_BUFFER | DESCRIPTOR_TYPE_BUFFER;
vbNormalDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
vbNormalDesc.mDesc.mVertexStride = sizeof(SceneVertexNormal);
vbNormalDesc.mDesc.mElementCount = pScene->totalVertices * (sizeof(SceneVertexNormal) / sizeof(uint32_t));
vbNormalDesc.mDesc.mStructStride = sizeof(uint32_t);
vbNormalDesc.mDesc.mSize = vbNormalDesc.mDesc.mElementCount * vbNormalDesc.mDesc.mStructStride;
vbNormalDesc.pData = pScene->normals.data();
vbNormalDesc.ppBuffer = &pVertexBufferNormal;
vbNormalDesc.mDesc.pDebugName = L"Vertex Normal Buffer Desc";
addResource(&vbNormalDesc);
// Vertex tangent buffer for the scene
BufferLoadDesc vbTangentDesc = {};
vbTangentDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_VERTEX_BUFFER | DESCRIPTOR_TYPE_BUFFER;
vbTangentDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
vbTangentDesc.mDesc.mVertexStride = sizeof(SceneVertexTangent);
vbTangentDesc.mDesc.mElementCount = pScene->totalVertices * (sizeof(SceneVertexTangent) / sizeof(uint32_t));
vbTangentDesc.mDesc.mStructStride = sizeof(uint32_t);
vbTangentDesc.mDesc.mSize = vbTangentDesc.mDesc.mElementCount * vbTangentDesc.mDesc.mStructStride;
vbTangentDesc.pData = pScene->tangents.data();
vbTangentDesc.ppBuffer = &pVertexBufferTangent;
vbTangentDesc.mDesc.pDebugName = L"Vertex Tangent Buffer Desc";
addResource(&vbTangentDesc);
LOGINFOF("Load scene buffers : %f ms", bufferLoadTimer.GetUSec(true) / 1000.0f);
/************************************************************************/
// Cluster creation
/************************************************************************/
HiresTimer clusterTimer;
// Calculate clusters
for (uint32_t i = 0; i < pScene->numMeshes; ++i)
{
MeshIn* mesh = pScene->meshes + i;
Material* material = pScene->materials + mesh->materialId;
CreateClusters(material->twoSided, pScene, mesh);
}
LOGINFOF("Load clusters : %f ms", clusterTimer.GetUSec(true) / 1000.0f);
/************************************************************************/
// Texture loading
/************************************************************************/
HiresTimer textureLoadTimer;
gDiffuseMaps = tinystl::vector<Texture*>(pScene->numMaterials);
gNormalMaps = tinystl::vector<Texture*>(pScene->numMaterials);
gSpecularMaps = tinystl::vector<Texture*>(pScene->numMaterials);
for (uint32_t i = 0; i < pScene->numMaterials; ++i)
{
TextureLoadDesc diffuse = {};
diffuse.pFilename = pScene->textures[i];
diffuse.mRoot = FSR_Textures;
diffuse.mUseMipmaps = true;
diffuse.ppTexture = &gDiffuseMaps[i];
diffuse.mSrgb = false;
addResource(&diffuse);
TextureLoadDesc normal = {};
normal.pFilename = pScene->normalMaps[i];
normal.mRoot = FSR_Textures;
normal.mUseMipmaps = true;
normal.ppTexture = &gNormalMaps[i];
addResource(&normal);
TextureLoadDesc specular = {};
specular.pFilename = pScene->specularMaps[i];
specular.mRoot = FSR_Textures;
specular.mUseMipmaps = true;
specular.ppTexture = &gSpecularMaps[i];
addResource(&specular);
}
LOGINFOF("Load textures : %f ms", textureLoadTimer.GetUSec(true) / 1000.0f);
/************************************************************************/
// Setup root signatures
/************************************************************************/
// Graphics root signatures
const char* pTextureSamplerName = "textureFilter";
const char* pShadingSamplerNames[] = { "depthSampler", "textureSampler" };
Sampler* pShadingSamplers[] = { pSamplerBilinearClamp, pSamplerBilinear };
const char* pAoSamplerName = "g_SamplePoint";
Shader* pShaders[gNumGeomSets * 2] = {};
for (uint32_t i = 0; i < gNumGeomSets; ++i)
{
pShaders[i * 2] = pShaderVisibilityBufferPass[i];
pShaders[i * 2 + 1] = pShaderShadowPass[i];
}
RootSignatureDesc vbRootDesc = { pShaders, gNumGeomSets * 2 };
vbRootDesc.mMaxBindlessTextures = pScene->numMaterials;
vbRootDesc.ppStaticSamplerNames = &pTextureSamplerName;
vbRootDesc.ppStaticSamplers = &pSamplerPointClamp;
vbRootDesc.mStaticSamplerCount = 1;
addRootSignature(pRenderer, &vbRootDesc, &pRootSignatureVBPass);
RootSignatureDesc deferredPassRootDesc = { pShaderDeferredPass, gNumGeomSets };
deferredPassRootDesc.mMaxBindlessTextures = pScene->numMaterials;
deferredPassRootDesc.ppStaticSamplerNames = &pTextureSamplerName;
deferredPassRootDesc.ppStaticSamplers = &pSamplerTrilinearAniso;
deferredPassRootDesc.mStaticSamplerCount = 1;
addRootSignature(pRenderer, &deferredPassRootDesc, &pRootSignatureDeferredPass);
RootSignatureDesc shadeRootDesc = { pShaderVisibilityBufferShade, 2 };
// Set max number of bindless textures in the root signature
shadeRootDesc.mMaxBindlessTextures = pScene->numMaterials;
shadeRootDesc.ppStaticSamplerNames = pShadingSamplerNames;
shadeRootDesc.ppStaticSamplers = pShadingSamplers;
shadeRootDesc.mStaticSamplerCount = 2;
addRootSignature(pRenderer, &shadeRootDesc, &pRootSignatureVBShade);
shadeRootDesc.ppShaders = pShaderDeferredShade;
addRootSignature(pRenderer, &shadeRootDesc, &pRootSignatureDeferredShade);
shadeRootDesc.ppShaders = &pShaderDeferredShadePointLight;
shadeRootDesc.mShaderCount = 1;
addRootSignature(pRenderer, &shadeRootDesc, &pRootSignatureDeferredShadePointLight);
RootSignatureDesc aoRootDesc = { pShaderAO, 4 };
aoRootDesc.ppStaticSamplerNames = &pAoSamplerName;
aoRootDesc.ppStaticSamplers = &pSamplerPointClamp;
aoRootDesc.mStaticSamplerCount = 1;
addRootSignature(pRenderer, &aoRootDesc, &pRootSignatureAO);
RootSignatureDesc resolveRootDesc = { &pShaderResolve, 1 };
addRootSignature(pRenderer, &resolveRootDesc, &pRootSignatureResolve);
RootSignatureDesc resolveGodrayRootDesc = { &pShaderGodrayResolve, 1 };
addRootSignature(pRenderer, &resolveGodrayRootDesc, &pRootSignatureGodrayResolve);
// Triangle filtering root signatures
RootSignatureDesc clearBuffersRootDesc = { &pShaderClearBuffers, 1 };
addRootSignature(pRenderer, &clearBuffersRootDesc, &pRootSignatureClearBuffers);
RootSignatureDesc triangleFilteringRootDesc = { &pShaderTriangleFiltering, 1 };
#if defined(VULKAN)
const char* pBatchBufferName = "batchData";
triangleFilteringRootDesc.mDynamicUniformBufferCount = 1;
triangleFilteringRootDesc.ppDynamicUniformBufferNames = &pBatchBufferName;
#endif
addRootSignature(pRenderer, &triangleFilteringRootDesc, &pRootSignatureTriangleFiltering);
#if !defined(METAL)
RootSignatureDesc batchCompactionRootDesc = { &pShaderBatchCompaction, 1 };
addRootSignature(pRenderer, &batchCompactionRootDesc, &pRootSignatureBatchCompaction);
#endif
RootSignatureDesc clearLightRootDesc = { &pShaderClearLightClusters, 1 };
addRootSignature(pRenderer, &clearLightRootDesc, &pRootSignatureClearLightClusters);
RootSignatureDesc clusterRootDesc = { &pShaderClusterLights, 1 };
addRootSignature(pRenderer, &clusterRootDesc, &pRootSignatureClusterLights);
RootSignatureDesc CurveConversionRootSigDesc = { &pShaderCurveConversion, 1 };
addRootSignature(pRenderer, &CurveConversionRootSigDesc, &pRootSigCurveConversionPass);
RootSignatureDesc sunPassShaderRootSigDesc = { &pSunPass, 1 };
addRootSignature(pRenderer, &sunPassShaderRootSigDesc, &pRootSigSunPass);
RootSignatureDesc godrayPassShaderRootSigDesc = { &pGodRayPass, 1 };
addRootSignature(pRenderer, &godrayPassShaderRootSigDesc, &pRootSigGodRayPass);
RootSignatureDesc finalShaderRootSigDesc = { &pShaderPresentPass, 1 };
addRootSignature(pRenderer, &finalShaderRootSigDesc, &pRootSigPresentPass);
/************************************************************************/
// Setup indirect command signatures
/************************************************************************/
#if defined(DIRECT3D12)
const DescriptorInfo* pDrawId = NULL;
IndirectArgumentDescriptor indirectArgs[2] = {};
indirectArgs[0].mType = INDIRECT_CONSTANT;
indirectArgs[0].mCount = 1;
indirectArgs[1].mType = INDIRECT_DRAW_INDEX;
CommandSignatureDesc vbPassDesc = { pCmdPool, pRootSignatureVBPass, 2, indirectArgs };
pDrawId = &pRootSignatureVBPass->pDescriptors[pRootSignatureVBPass->pDescriptorNameToIndexMap[tinystl::hash("indirectRootConstant")]];
indirectArgs[0].mRootParameterIndex = pRootSignatureVBPass->pDxRootConstantRootIndices[pDrawId->mIndexInParent];
addIndirectCommandSignature(pRenderer, &vbPassDesc, &pCmdSignatureVBPass);
CommandSignatureDesc deferredPassDesc = { pCmdPool, pRootSignatureDeferredPass, 2, indirectArgs };
pDrawId = &pRootSignatureDeferredPass->pDescriptors[pRootSignatureDeferredPass->pDescriptorNameToIndexMap[tinystl::hash("indirectRootConstant")]];
indirectArgs[0].mRootParameterIndex = pRootSignatureDeferredPass->pDxRootConstantRootIndices[pDrawId->mIndexInParent];
addIndirectCommandSignature(pRenderer, &deferredPassDesc, &pCmdSignatureDeferredPass);
#else
// Indicate the renderer that we want to use non-indexed geometry. We can't use indices because Metal doesn't provide triangle ID built-in
// variable in the pixel shader. So, the only way to workaround this is to replicate vertices and use vertex_id from the vertex shader to
// calculate the triangle ID (triangleId = vertexId / 3). This is not the optimal approach but works as a workaround.
IndirectArgumentDescriptor indirectArgs[1] = {};
#if defined(METAL)
indirectArgs[0].mType = INDIRECT_DRAW;
#else
indirectArgs[0].mType = INDIRECT_DRAW_INDEX;
#endif
CommandSignatureDesc vbPassDesc = { pCmdPool, pRootSignatureVBPass, 1, indirectArgs };
CommandSignatureDesc deferredPassDesc = { pCmdPool, pRootSignatureDeferredPass, 1, indirectArgs };
addIndirectCommandSignature(pRenderer, &vbPassDesc, &pCmdSignatureVBPass);
addIndirectCommandSignature(pRenderer, &deferredPassDesc, &pCmdSignatureDeferredPass);
#endif
// Create geometry for light rendering
createCubeBuffers(pRenderer, pCmdPool, &pVertexBufferCube, &pIndexBufferCube);
/************************************************************************/
// Setup compute pipelines for triangle filtering
/************************************************************************/
ComputePipelineDesc pipelineDesc = { pShaderClearBuffers, pRootSignatureClearBuffers };
addComputePipeline(pRenderer, &pipelineDesc, &pPipelineClearBuffers);
// Create the compute pipeline for GPU triangle filtering
pipelineDesc = { pShaderTriangleFiltering, pRootSignatureTriangleFiltering };
addComputePipeline(pRenderer, &pipelineDesc, &pPipelineTriangleFiltering);
#ifndef METAL
pipelineDesc = { pShaderBatchCompaction, pRootSignatureBatchCompaction };
addComputePipeline(pRenderer, &pipelineDesc, &pPipelineBatchCompaction);
#endif
// Setup the clearing light clusters pipeline
pipelineDesc = { pShaderClearLightClusters, pRootSignatureClearLightClusters };
addComputePipeline(pRenderer, &pipelineDesc, &pPipelineClearLightClusters);
// Setup the compute the light clusters pipeline
pipelineDesc = { pShaderClusterLights, pRootSignatureClusterLights };
addComputePipeline(pRenderer, &pipelineDesc, &pPipelineClusterLights);
/************************************************************************/
// Setup the UI components for text rendering, UI controls...
/************************************************************************/
if (!gAppUI.Init(pRenderer))
return false;
gAppUI.LoadFont("TitilliumText/TitilliumText-Bold.otf", FSR_Builtin_Fonts);
GuiDesc guiDesc = {};
guiDesc.mStartPosition = vec2(225.0f, 100.0f);
pGuiWindow = gAppUI.AddGuiComponent(GetName(), &guiDesc);
#if !defined(TARGET_IOS)
CheckboxWidget vsyncProp("Toggle VSync", &gToggleVSync);
pGuiWindow->AddWidget(vsyncProp);
#endif
#if !defined(METAL)
static const char* outputModeNames[] = {
"SDR",
"HDR10 (DirectX 12 Only)",
nullptr
};
static const OutputMode outputModeValues[] = {
OUTPUT_MODE_SDR,
OUTPUT_MODE_HDR10,
};
DropdownWidget outputMode("Output Mode", (uint32_t*)& gAppSettings.mOutputMode, outputModeNames, (uint32_t*)outputModeValues, 2U);
pGuiWindow->AddWidget(outputMode);
#else
static const char* outputModeNames[] = {
"SDR",
nullptr
};
static const OutputMode outputModeValues[] = {
OUTPUT_MODE_SDR
};
DropdownWidget outputMode("Output Mode", (uint32_t*)& gAppSettings.mOutputMode, outputModeNames, (uint32_t*)outputModeValues, 1U);
pGuiWindow->AddWidget(outputMode);
#endif
static const char* lightingModeNames[] = {
"Phong",
"Physically Based Rendering",
nullptr
};
static const LightingMode lightingModeValues[] = {
LIGHTING_PHONG,
LIGHTING_PBR,
};
DropdownWidget lightingMode("Lighting Mode", (uint32_t*)& gAppSettings.mLightingMode, lightingModeNames, (uint32_t*)lightingModeValues, 2U);
pGuiWindow->AddWidget(lightingMode);
CheckboxWidget cameraProp("Cinematic Camera walking", &gAppSettings.cameraWalking);
pGuiWindow->AddWidget(cameraProp);
SliderFloatWidget cameraSpeedProp("Cinematic Camera walking: Speed", &gAppSettings.cameraWalkingSpeed, 0.0f, 3.0f);
pGuiWindow->AddWidget(cameraSpeedProp);
// Light Settings
//---------------------------------------------------------------------------------
// offset max angle for sun control so the light won't bleed with
// small glancing angles, i.e., when lightDir is almost parallel to the plane
SliderFloat2Widget sunX("Sun Control", &gAppSettings.mSunControl, float2(-PI), float2(PI), float2(0.001f));
pGuiWindow->AddWidget(sunX);
gAppSettings.gGodrayInfo.exposure = 0.06f;
gAppSettings.gGodrayInfo.decay = 0.9f;
gAppSettings.gGodrayInfo.density = 2.0f;
gAppSettings.gGodrayInfo.weight = 1.4f;
gAppSettings.gGodrayInfo.NUM_SAMPLES = 80;
SliderFloat4Widget lightColorUI("Light Color & Intensity", &gAppSettings.mLightColor, 0.0f, 30.0f, 0.01f);
pGuiWindow->AddWidget(lightColorUI);
CheckboxWidget toggleGR("Enable Godray", &gAppSettings.mEnableGodray);
pGuiWindow->AddWidget(toggleGR);
tinystl::vector<IWidget*>& dynamicPropsGR = gAppSettings.mDynamicUIControlsGR.mDynamicProperties; // shorthand
dynamicPropsGR.emplace_back(SliderFloatWidget("God Ray : Sun Size", &gAppSettings.mSunSize, 1.0f, 1000.0f).Clone());
dynamicPropsGR.emplace_back(SliderFloatWidget("God Ray: Exposure", &gAppSettings.gGodrayInfo.exposure, 0.0f, 0.1f, 0.001f).Clone());
dynamicPropsGR.emplace_back(SliderUintWidget("God Ray: Quality", &gAppSettings.gGodrayInteration, 1, 4).Clone());
if (gAppSettings.mEnableGodray)
gAppSettings.mDynamicUIControlsGR.ShowDynamicProperties(pGuiWindow);
//SliderFloatWidget esm("Shadow Control", &gAppSettings.mEsmControl, 0, 200.0f);
//pGuiWindow->AddWidget(esm);
CheckboxWidget localLight("Enable Random Point Lights", &gAppSettings.mRenderLocalLights);
pGuiWindow->AddWidget(localLight);
#if !defined(_DURANGO) && !defined(METAL) && !defined(__linux__)
Resolution wantedResolutions[] = { { 3840, 2160 }, { 1920, 1080 }, { 1280, 720 }, { 1024, 768 } };
gResolutions.emplace_back(getMonitor(0)->defaultResolution);
for (uint32_t i = 0; i < sizeof(wantedResolutions) / sizeof(wantedResolutions[0]); ++i)
{
bool duplicate = false;
for (uint32_t j = 0; j < (uint32_t)gResolutions.size(); ++j)
{
if (wantedResolutions[i].mWidth == gResolutions[j].mWidth && wantedResolutions[i].mHeight == gResolutions[j].mHeight)
{
duplicate = true;
break;
}
}
if (!duplicate && getResolutionSupport(getMonitor(0), &wantedResolutions[i]))
{
gResolutions.emplace_back(wantedResolutions[i]);
}
}
gResolutionProperty =
addResolutionProperty(pGuiWindow, gResolutionIndex, (uint32_t)gResolutions.size(), gResolutions.data(), []()
{
gResolutionChange = true;
});
#endif
/************************************************************************/
// Rendering Settings
/************************************************************************/
static const char* renderModeNames[] = {
"Visibility Buffer",
"Deferred Shading",
nullptr
};
static const RenderMode renderModeValues[] = {
RENDERMODE_VISBUFF,
RENDERMODE_DEFERRED,
};
DropdownWidget renderMode("Render Mode", (uint32_t*)&gAppSettings.mRenderMode, renderModeNames, (uint32_t*)renderModeValues, 2U);
pGuiWindow->AddWidget(renderMode);
static const char* displayColorRangeNames[] = {
"RGB",
nullptr
};
static const DisplayColorRange displayColorRangeValues[] = {
ColorRange_RGB
};
static const char* displaySignalRangeNames[] = {
"Range Full",
"Range Limited",
nullptr
};
static const DisplaySignalRange displaySignalRangeValues[] = {
Display_SIGNAL_RANGE_FULL,
Display_SIGNAL_RANGE_NARROW
};
static const char* displayColorSpaceNames[] = {
"ColorSpace Rec709",
"ColorSpace Rec2020",
"ColorSpace P3D65",
nullptr
};
static const DisplayColorSpace displayColorSpaceValues[] = {
ColorSpace_Rec709,
ColorSpace_Rec2020,
ColorSpace_P3D65
};
tinystl::vector<IWidget*>& displaySetting = gAppSettings.mDisplaySetting.mDynamicProperties;
displaySetting.emplace_back(DropdownWidget("Display Color Range", (uint32_t*)& gAppSettings.mDisplayColorRange, displayColorRangeNames, (uint32_t*)displayColorRangeValues, 1U).Clone());
displaySetting.emplace_back(DropdownWidget("Display Signal Range", (uint32_t*)& gAppSettings.mDisplaySignalRange, displaySignalRangeNames, (uint32_t*)displaySignalRangeValues, 2U).Clone());
displaySetting.emplace_back(DropdownWidget("Display Color Space", (uint32_t*)& gAppSettings.mCurrentSwapChainColorSpace, displayColorSpaceNames, (uint32_t*)displayColorSpaceValues, 3U).Clone());
CheckboxWidget holdProp("Hold filtered results", &gAppSettings.mHoldFilteredResults);
pGuiWindow->AddWidget(holdProp);
CheckboxWidget filtering("Triangle Filtering", &gAppSettings.mFilterTriangles);
pGuiWindow->AddWidget(filtering);
CheckboxWidget cluster("Cluster Culling", &gAppSettings.mClusterCulling);
pGuiWindow->AddWidget(cluster);
CheckboxWidget asyncCompute("Async Compute", &gAppSettings.mAsyncCompute);
pGuiWindow->AddWidget(asyncCompute);
#if MSAASAMPLECOUNT == 1
CheckboxWidget debugTargets("Draw Debug Targets", &gAppSettings.mDrawDebugTargets);
pGuiWindow->AddWidget(debugTargets);
#endif
/************************************************************************/
// HDAO Settings
/************************************************************************/
CheckboxWidget toggleAO("Enable HDAO", &gAppSettings.mEnableHDAO);
pGuiWindow->AddWidget(toggleAO);
tinystl::vector<IWidget*>& dynamicPropsAO = gAppSettings.mDynamicUIControlsAO.mDynamicProperties; // shorthand
dynamicPropsAO.emplace_back(SliderFloatWidget("AO accept radius", &gAppSettings.mAcceptRadius, 0, 10).Clone());
dynamicPropsAO.emplace_back(SliderFloatWidget("AO reject radius", &gAppSettings.mRejectRadius, 0, 10).Clone());
dynamicPropsAO.emplace_back(SliderFloatWidget("AO intensity radius", &gAppSettings.mAOIntensity, 0, 10).Clone());
dynamicPropsAO.emplace_back(SliderIntWidget("AO Quality", &gAppSettings.mAOQuality, 1, 4).Clone());
if (gAppSettings.mEnableHDAO)
gAppSettings.mDynamicUIControlsAO.ShowDynamicProperties(pGuiWindow);
static const char* curveConversionModeNames[] = {
"Linear Scale",
"Scurve",
nullptr
};
static const CurveConversionMode curveConversionValues[] = {
CurveConversion_LinearScale,
CurveConversion_SCurve
};
DropdownWidget curveConversionMode("Curve Conversion", (uint32_t*)& gAppSettings.mCurveConversionMode, curveConversionModeNames, (uint32_t*)curveConversionValues, 2U);
pGuiWindow->AddWidget(curveConversionMode);
tinystl::vector<IWidget*>& dynamicPropsLinearScale = gAppSettings.mLinearScale.mDynamicProperties;
dynamicPropsLinearScale.emplace_back(SliderFloatWidget("Linear Scale", &gAppSettings.LinearScale, 0, 300.0f).Clone());
if (gAppSettings.mCurveConversionMode == CurveConversion_LinearScale)
{
gAppSettings.mLinearScale.ShowDynamicProperties(pGuiWindow);
}
tinystl::vector<IWidget*>& dynamicPropsSCurve = gAppSettings.mSCurve.mDynamicProperties; // shorthand
dynamicPropsSCurve.emplace_back(SliderFloatWidget("SCurve: Scale Factor", &gAppSettings.SCurveScaleFactor, 0, 10.0f).Clone());
dynamicPropsSCurve.emplace_back(SliderFloatWidget("SCurve: SMin", &gAppSettings.SCurveSMin, 0, 2.0f).Clone());
dynamicPropsSCurve.emplace_back(SliderFloatWidget("SCurve: SMid", &gAppSettings.SCurveSMid, 0, 20.0f).Clone());
dynamicPropsSCurve.emplace_back(SliderFloatWidget("SCurve: SMax", &gAppSettings.SCurveSMax, 0, 100.0f).Clone());
dynamicPropsSCurve.emplace_back(SliderFloatWidget("SCurve: TMin", &gAppSettings.SCurveTMin, 0, 10.0f).Clone());
dynamicPropsSCurve.emplace_back(SliderFloatWidget("SCurve: TMid", &gAppSettings.SCurveTMid, 0, 300.0f).Clone());
dynamicPropsSCurve.emplace_back(SliderFloatWidget("SCurve: TMax", &gAppSettings.SCurveTMax, 0, 4000.0f).Clone());
dynamicPropsSCurve.emplace_back(SliderFloatWidget("SCurve: Slope Factor", &gAppSettings.SCurveSlopeFactor, 0, 3.0f).Clone());
if (gAppSettings.mOutputMode != OutputMode::OUTPUT_MODE_SDR && gAppSettings.mCurveConversionMode == CurveConversion_SCurve)
{
gAppSettings.mSCurve.ShowDynamicProperties(pGuiWindow);
gSCurveInfomation.UseSCurve = 1.0f;
}
#if !defined(_DURANGO) && !defined(METAL) && !defined(__linux__)
if (!pWindow->fullScreen)
pGuiWindow->RemoveWidget(gResolutionProperty);
#endif
/************************************************************************/
// Setup the fps camera for navigating through the scene
/************************************************************************/
vec3 startPosition(600.0f, 490.0f, 70.0f);
vec3 startLookAt = startPosition + vec3(-1.0f - 0.0f, 0.1f, 0.0f);
CameraMotionParameters camParams;
camParams.acceleration = 1300 * 2.5f;
camParams.braking = 1300 * 2.5f;
camParams.maxSpeed = 200 * 2.5f;
pCameraController = createFpsCameraController(startPosition, startLookAt);
pCameraController->setMotionParameters(camParams);
requestMouseCapture(true);
/************************************************************************/
/************************************************************************/
// Finish the resource loading process since the next code depends on the loaded resources
finishResourceLoading();
gDiffuseMapsStorage = (Texture*)conf_malloc(sizeof(Texture) * gDiffuseMaps.size());
gNormalMapsStorage = (Texture*)conf_malloc(sizeof(Texture) * gNormalMaps.size());
gSpecularMapsStorage = (Texture*)conf_malloc(sizeof(Texture) * gSpecularMaps.size());
for (uint32_t i = 0; i < (uint32_t)gDiffuseMaps.size(); ++i)
{
memcpy(&gDiffuseMapsStorage[i], gDiffuseMaps[i], sizeof(Texture));
gDiffuseMapsPacked.push_back(&gDiffuseMapsStorage[i]);
}
for (uint32_t i = 0; i < (uint32_t)gDiffuseMaps.size(); ++i)
{
memcpy(&gNormalMapsStorage[i], gNormalMaps[i], sizeof(Texture));
gNormalMapsPacked.push_back(&gNormalMapsStorage[i]);
}
for (uint32_t i = 0; i < (uint32_t)gDiffuseMaps.size(); ++i)
{
memcpy(&gSpecularMapsStorage[i], gSpecularMaps[i], sizeof(Texture));
gSpecularMapsPacked.push_back(&gSpecularMapsStorage[i]);
}
HiresTimer setupBuffersTimer;
addTriangleFilteringBuffers();
LOGINFOF("Setup buffers : %f ms", setupBuffersTimer.GetUSec(true) / 1000.0f);
#ifdef _DURANGO
// When async compute is on, we need to transition some resources in the graphics queue
// because they can't be transitioned by the compute queue (incompatible)
if (gAppSettings.mAsyncCompute)
setResourcesToComputeCompliantState(0, true);
#endif
LOGINFOF("Total Load Time : %f ms", timer.GetUSec(true) / 1000.0f);
InputSystem::RegisterInputEvent(onInputEventHandler);
return true;
}
void Exit()
{
removeResource(pSkybox);
removeTriangleFilteringBuffers();
destroyCameraController(pCameraController);
removeDebugRendererInterface();
gAppSettings.mDynamicUIControlsAO.Destroy();
gAppUI.Exit();
// Destroy geometry for light rendering
destroyBuffers(pRenderer, pVertexBufferCube, pIndexBufferCube);
// Destroy triangle filtering pipelines
removePipeline(pRenderer, pPipelineClusterLights);
removePipeline(pRenderer, pPipelineClearLightClusters);
removePipeline(pRenderer, pPipelineTriangleFiltering);
#if !defined(METAL)
removePipeline(pRenderer, pPipelineBatchCompaction);
#endif
removePipeline(pRenderer, pPipelineClearBuffers);
removeRootSignature(pRenderer, pRootSignatureResolve);
removeRootSignature(pRenderer, pRootSignatureGodrayResolve);
removeRootSignature(pRenderer, pRootSignatureAO);
removeRootSignature(pRenderer, pRootSingatureSkybox);
removeRootSignature(pRenderer, pRootSigSunPass);
removeRootSignature(pRenderer, pRootSigGodRayPass);
removeRootSignature(pRenderer, pRootSigCurveConversionPass);
removeRootSignature(pRenderer, pRootSigPresentPass);
removeRootSignature(pRenderer, pRootSignatureClusterLights);
removeRootSignature(pRenderer, pRootSignatureClearLightClusters);
#if !defined(METAL)
removeRootSignature(pRenderer, pRootSignatureBatchCompaction);
#endif
removeRootSignature(pRenderer, pRootSignatureTriangleFiltering);
removeRootSignature(pRenderer, pRootSignatureClearBuffers);
removeRootSignature(pRenderer, pRootSignatureDeferredShadePointLight);
removeRootSignature(pRenderer, pRootSignatureDeferredShade);
removeRootSignature(pRenderer, pRootSignatureDeferredPass);
removeRootSignature(pRenderer, pRootSignatureVBShade);
removeRootSignature(pRenderer, pRootSignatureVBPass);
removeIndirectCommandSignature(pRenderer, pCmdSignatureDeferredPass);
removeIndirectCommandSignature(pRenderer, pCmdSignatureVBPass);
/************************************************************************/
// Remove loaded scene
/************************************************************************/
// Destroy scene buffers
#if !defined(METAL)
removeResource(pIndexBufferAll);
#endif
removeResource(pVertexBufferPosition);
removeResource(pVertexBufferTexCoord);
removeResource(pVertexBufferNormal);
removeResource(pVertexBufferTangent);
removeResource(pSunVertexBuffer);
removeResource(pSunIndexBuffer);
removeResource(pSkyboxVertexBuffer);
// Destroy clusters
for (uint32_t i = 0; i < pScene->numMeshes; ++i)
{
conf_free(pScene->meshes[i].clusters);
conf_free(pScene->meshes[i].clusterCompacts);
}
// Remove Textures
for (uint32_t i = 0; i < pScene->numMaterials; ++i)
{
removeResource(gDiffuseMaps[i]);
removeResource(gNormalMaps[i]);
removeResource(gSpecularMaps[i]);
}
removeScene(pScene);
conf_free(gDiffuseMapsStorage);
conf_free(gNormalMapsStorage);
conf_free(gSpecularMapsStorage);
/************************************************************************/
/************************************************************************/
removeShaders();
removeSemaphore(pRenderer, pImageAcquiredSemaphore);
removeFence(pRenderer, pTransitionFences);
removeCmd_n(pCmdPool, gImageCount, ppCmds);
removeCmdPool(pRenderer, pCmdPool);
removeQueue(pGraphicsQueue);
removeCmd_n(pComputeCmdPool, gImageCount, ppComputeCmds);
removeCmdPool(pRenderer, pComputeCmdPool);
removeQueue(pComputeQueue);
removeSampler(pRenderer, pSamplerTrilinearAniso);
removeSampler(pRenderer, pSamplerBilinear);
removeSampler(pRenderer, pSamplerPointClamp);
removeSampler(pRenderer, pSamplerBilinearClamp);
removeBlendState(pBlendStateOneZero);
removeBlendState(pBlendStateSkyBox);
removeDepthState(pDepthStateEnable);
removeDepthState(pDepthStateDisable);
removeRasterizerState(pRasterizerStateCullBack);
removeRasterizerState(pRasterizerStateCullFront);
removeRasterizerState(pRasterizerStateCullNone);
removeRasterizerState(pRasterizerStateCullBackMS);
removeRasterizerState(pRasterizerStateCullFrontMS);
removeRasterizerState(pRasterizerStateCullNoneMS);
removeGpuProfiler(pRenderer, pGraphicsGpuProfiler);
removeGpuProfiler(pRenderer, pComputeGpuProfiler);
removeResourceLoaderInterface(pRenderer);
/*
#ifdef _DEBUG
ID3D12DebugDevice *pDebugDevice = NULL;
pRenderer->pDxDevice->QueryInterface(&pDebugDevice);
pDebugDevice->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL | D3D12_RLDO_IGNORE_INTERNAL);
pDebugDevice->Release();
#endif
*/
removeRenderer(pRenderer);
}
// Setup the render targets used in this demo.
// The only render target that is being currently used stores the results of the Visibility Buffer pass.
// As described earlier, this render target uses 32 bit per pixel to store draw / triangle IDs that will be
// loaded later by the shade step to reconstruct interpolated triangle data per pixel.
bool Load()
{
for (uint32_t i = 0; i < gImageCount; ++i)
{
addFence(pRenderer, &pRenderCompleteFences[i]);
addFence(pRenderer, &pComputeCompleteFences[i]);
addSemaphore(pRenderer, &pRenderCompleteSemaphores[i]);
addSemaphore(pRenderer, &pComputeCompleteSemaphores[i]);
}
gFrameCount = 0;
if (!addRenderTargets())
return false;
if (!gAppUI.Load(pSwapChain->ppSwapchainRenderTargets))
return false;
#if defined(DIRECT3D12)
if (gAppSettings.mOutputMode == OUTPUT_MODE_HDR10)
{
SetHDRMetaData(gAppSettings.MaxOutputNits, gAppSettings.MinOutputNits, gAppSettings.MaxCLL, gAppSettings.MaxFALL);
}
#endif
/************************************************************************/
// Vertex layout used by all geometry passes (shadow, visibility, deferred)
/************************************************************************/
#if !defined(METAL)
#if defined(__linux__)
VertexLayout vertexLayout = {};
vertexLayout.mAttribCount = 4;
vertexLayout.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayout.mAttribs[0].mFormat = ImageFormat::RGB32F;
vertexLayout.mAttribs[0].mBinding = 0;
vertexLayout.mAttribs[0].mLocation = 0;
vertexLayout.mAttribs[1].mSemantic = SEMANTIC_TEXCOORD0;
vertexLayout.mAttribs[1].mFormat = ImageFormat::RG32F;
vertexLayout.mAttribs[1].mBinding = 1;
vertexLayout.mAttribs[1].mLocation = 1;
vertexLayout.mAttribs[2].mSemantic = SEMANTIC_NORMAL;
vertexLayout.mAttribs[2].mFormat = ImageFormat::RGB32F;
vertexLayout.mAttribs[2].mBinding = 2;
vertexLayout.mAttribs[2].mLocation = 2;
vertexLayout.mAttribs[3].mSemantic = SEMANTIC_TANGENT;
vertexLayout.mAttribs[3].mFormat = ImageFormat::RGB32F;
vertexLayout.mAttribs[3].mBinding = 3;
vertexLayout.mAttribs[3].mLocation = 3;
VertexLayout vertexLayoutPosAndTex = {};
vertexLayoutPosAndTex.mAttribCount = 2;
vertexLayoutPosAndTex.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayoutPosAndTex.mAttribs[0].mFormat = ImageFormat::RGB32F;
vertexLayoutPosAndTex.mAttribs[0].mBinding = 0;
vertexLayoutPosAndTex.mAttribs[0].mLocation = 0;
vertexLayoutPosAndTex.mAttribs[1].mSemantic = SEMANTIC_TEXCOORD0;
vertexLayoutPosAndTex.mAttribs[1].mFormat = ImageFormat::RG32F;
vertexLayoutPosAndTex.mAttribs[1].mBinding = 1;
vertexLayoutPosAndTex.mAttribs[1].mLocation = 1;
// Position only vertex stream that is used in shadow opaque pass
VertexLayout vertexLayoutPositionOnly = {};
vertexLayoutPositionOnly.mAttribCount = 1;
vertexLayoutPositionOnly.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayoutPositionOnly.mAttribs[0].mFormat = ImageFormat::RGB32F;
vertexLayoutPositionOnly.mAttribs[0].mBinding = 0;
vertexLayoutPositionOnly.mAttribs[0].mLocation = 0;
vertexLayoutPositionOnly.mAttribs[0].mOffset = 0;
#else
VertexLayout vertexLayout = {};
vertexLayout.mAttribCount = 4;
vertexLayout.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayout.mAttribs[0].mFormat = ImageFormat::RGB32F;
vertexLayout.mAttribs[0].mBinding = 0;
vertexLayout.mAttribs[0].mLocation = 0;
vertexLayout.mAttribs[1].mSemantic = SEMANTIC_TEXCOORD0;
vertexLayout.mAttribs[1].mFormat = ImageFormat::R32UI;
vertexLayout.mAttribs[1].mBinding = 1;
vertexLayout.mAttribs[1].mLocation = 1;
vertexLayout.mAttribs[2].mSemantic = SEMANTIC_NORMAL;
vertexLayout.mAttribs[2].mFormat = ImageFormat::R32UI;
vertexLayout.mAttribs[2].mBinding = 2;
vertexLayout.mAttribs[2].mLocation = 2;
vertexLayout.mAttribs[3].mSemantic = SEMANTIC_TANGENT;
vertexLayout.mAttribs[3].mFormat = ImageFormat::R32UI;
vertexLayout.mAttribs[3].mBinding = 3;
vertexLayout.mAttribs[3].mLocation = 3;
VertexLayout vertexLayoutPosAndTex = {};
vertexLayoutPosAndTex.mAttribCount = 2;
vertexLayoutPosAndTex.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayoutPosAndTex.mAttribs[0].mFormat = ImageFormat::RGB32F;
vertexLayoutPosAndTex.mAttribs[0].mBinding = 0;
vertexLayoutPosAndTex.mAttribs[0].mLocation = 0;
vertexLayoutPosAndTex.mAttribs[1].mSemantic = SEMANTIC_TEXCOORD0;
vertexLayoutPosAndTex.mAttribs[1].mFormat = ImageFormat::R32UI;
vertexLayoutPosAndTex.mAttribs[1].mBinding = 1;
vertexLayoutPosAndTex.mAttribs[1].mLocation = 1;
// Position only vertex stream that is used in shadow opaque pass
VertexLayout vertexLayoutPositionOnly = {};
vertexLayoutPositionOnly.mAttribCount = 1;
vertexLayoutPositionOnly.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayoutPositionOnly.mAttribs[0].mFormat = ImageFormat::RGB32F;
vertexLayoutPositionOnly.mAttribs[0].mBinding = 0;
vertexLayoutPositionOnly.mAttribs[0].mLocation = 0;
vertexLayoutPositionOnly.mAttribs[0].mOffset = 0;
#endif
#endif
/************************************************************************/
// Setup the Shadow Pass Pipeline
/************************************************************************/
// Setup pipeline settings
GraphicsPipelineDesc shadowPipelineSettings = {};
shadowPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
shadowPipelineSettings.pDepthState = pDepthStateEnable;
shadowPipelineSettings.mDepthStencilFormat = pRenderTargetShadow->mDesc.mFormat;
shadowPipelineSettings.mSampleCount = pRenderTargetShadow->mDesc.mSampleCount;
shadowPipelineSettings.mSampleQuality = pRenderTargetShadow->mDesc.mSampleQuality;
shadowPipelineSettings.pRootSignature = pRootSignatureVBPass;
#if (MSAASAMPLECOUNT > 1)
shadowPipelineSettings.pRasterizerState = pRasterizerStateCullFrontMS;
#else
shadowPipelineSettings.pRasterizerState = pRasterizerStateCullFront;
#endif
#if !defined(METAL)
shadowPipelineSettings.pVertexLayout = &vertexLayoutPositionOnly;
#endif
shadowPipelineSettings.pShaderProgram = pShaderShadowPass[0];
addPipeline(pRenderer, &shadowPipelineSettings, &pPipelineShadowPass[0]);
#if !defined(METAL)
shadowPipelineSettings.pVertexLayout = &vertexLayoutPosAndTex;
#endif
shadowPipelineSettings.pShaderProgram = pShaderShadowPass[1];
addPipeline(pRenderer, &shadowPipelineSettings, &pPipelineShadowPass[1]);
/************************************************************************/
// Setup the Visibility Buffer Pass Pipeline
/************************************************************************/
// Setup pipeline settings
GraphicsPipelineDesc vbPassPipelineSettings = {};
vbPassPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
vbPassPipelineSettings.mRenderTargetCount = 1;
vbPassPipelineSettings.pDepthState = pDepthStateEnable;
vbPassPipelineSettings.pColorFormats = &pRenderTargetVBPass->mDesc.mFormat;
vbPassPipelineSettings.pSrgbValues = &pRenderTargetVBPass->mDesc.mSrgb;
vbPassPipelineSettings.mSampleCount = pRenderTargetVBPass->mDesc.mSampleCount;
vbPassPipelineSettings.mSampleQuality = pRenderTargetVBPass->mDesc.mSampleQuality;
vbPassPipelineSettings.mDepthStencilFormat = pDepthBuffer->mDesc.mFormat;
vbPassPipelineSettings.pRootSignature = pRootSignatureVBPass;
#if !defined(METAL)
vbPassPipelineSettings.pVertexLayout = &vertexLayoutPosAndTex;
#endif
for (uint32_t i = 0; i < gNumGeomSets; ++i)
{
#if !defined(METAL)
if (i == GEOMSET_OPAQUE)
vbPassPipelineSettings.pVertexLayout = &vertexLayoutPositionOnly;
else
vbPassPipelineSettings.pVertexLayout = &vertexLayoutPosAndTex;
#endif
#if (MSAASAMPLECOUNT > 1)
vbPassPipelineSettings.pRasterizerState = i == GEOMSET_ALPHATESTED ? pRasterizerStateCullNoneMS : pRasterizerStateCullFrontMS;
#else
vbPassPipelineSettings.pRasterizerState = i == GEOMSET_ALPHATESTED ? pRasterizerStateCullNone : pRasterizerStateCullFront;
#endif
vbPassPipelineSettings.pShaderProgram = pShaderVisibilityBufferPass[i];
#if defined(_DURANGO)
ExtendedGraphicsPipelineDesc edescs[2] = {};
edescs[0].type = EXTENDED_GRAPHICS_PIPELINE_TYPE_SHADER_LIMITS;
initExtendedGraphicsShaderLimits(&edescs[0].shaderLimitsDesc);
edescs[0].shaderLimitsDesc.maxWavesWithLateAllocParameterCache = 16;
edescs[1].type = EXTENDED_GRAPHICS_PIPELINE_TYPE_DEPTH_STENCIL_OPTIONS;
edescs[1].pixelShaderOptions.outOfOrderRasterization = PIXEL_SHADER_OPTION_OUT_OF_ORDER_RASTERIZATION_ENABLE_WATER_MARK_7;
if (i == 0)
edescs[1].pixelShaderOptions.depthBeforeShader = PIXEL_SHADER_OPTION_DEPTH_BEFORE_SHADER_ENABLE;
addPipelineExt(
pRenderer,
&vbPassPipelineSettings,
_countof(edescs),
edescs,
&pPipelineVisibilityBufferPass[i]);
#else
addPipeline(pRenderer, &vbPassPipelineSettings, &pPipelineVisibilityBufferPass[i]);
#endif
}
/************************************************************************/
// Setup the resources needed for the Visibility Buffer Shade Pipeline
/************************************************************************/
// Create pipeline
// Note: the vertex layout is set to null because the positions of the fullscreen triangle are being calculated automatically
// in the vertex shader using each vertex_id.
GraphicsPipelineDesc vbShadePipelineSettings = {};
vbShadePipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
vbShadePipelineSettings.mRenderTargetCount = 1;
vbShadePipelineSettings.pDepthState = pDepthStateDisable;
#if (MSAASAMPLECOUNT > 1)
vbShadePipelineSettings.pRasterizerState = pRasterizerStateCullNoneMS;
#else
vbShadePipelineSettings.pRasterizerState = pRasterizerStateCullNone;
#endif
vbShadePipelineSettings.pRootSignature = pRootSignatureVBShade;
for (uint32_t i = 0; i < 2; ++i)
{
vbShadePipelineSettings.pShaderProgram = pShaderVisibilityBufferShade[i];
vbShadePipelineSettings.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
#if (MSAASAMPLECOUNT > 1)
vbShadePipelineSettings.pColorFormats = &pRenderTargetMSAA->mDesc.mFormat;
vbShadePipelineSettings.pSrgbValues = &pRenderTargetMSAA->mDesc.mSrgb;
vbShadePipelineSettings.mSampleQuality = pRenderTargetMSAA->mDesc.mSampleQuality;
#else
//vbShadePipelineSettings.pColorFormats = &pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mFormat;
vbShadePipelineSettings.pColorFormats = &pIntermediateRenderTarget->mDesc.mFormat;
vbShadePipelineSettings.pSrgbValues = &pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSrgb;
vbShadePipelineSettings.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
#endif
#if defined(_DURANGO) && 1
ExtendedGraphicsPipelineDesc edescs[2];
memset(edescs, 0, sizeof(edescs));
edescs[0].type = EXTENDED_GRAPHICS_PIPELINE_TYPE_SHADER_LIMITS;
initExtendedGraphicsShaderLimits(&edescs[0].shaderLimitsDesc);
//edescs[0].ShaderLimitsDesc.MaxWavesWithLateAllocParameterCache = 22;
edescs[1].type = EXTENDED_GRAPHICS_PIPELINE_TYPE_DEPTH_STENCIL_OPTIONS;
edescs[1].pixelShaderOptions.outOfOrderRasterization = PIXEL_SHADER_OPTION_OUT_OF_ORDER_RASTERIZATION_ENABLE_WATER_MARK_7;
if (i == 0)
edescs[1].pixelShaderOptions.depthBeforeShader = PIXEL_SHADER_OPTION_DEPTH_BEFORE_SHADER_ENABLE;
addPipelineExt(
pRenderer,
&vbShadePipelineSettings,
_countof(edescs),
edescs,
&pPipelineVisibilityBufferShadeSrgb[i]);
#else
addPipeline(pRenderer, &vbShadePipelineSettings, &pPipelineVisibilityBufferShadeSrgb[i]);
#endif
}
/************************************************************************/
// Setup the resources needed for the Deferred Pass Pipeline
/************************************************************************/
ImageFormat::Enum deferredFormats[DEFERRED_RT_COUNT] = {};
bool deferredSrgb[DEFERRED_RT_COUNT] = {};
for (uint32_t i = 0; i < DEFERRED_RT_COUNT; ++i)
{
deferredFormats[i] = pRenderTargetDeferredPass[i]->mDesc.mFormat;
deferredSrgb[i] = pRenderTargetDeferredPass[i]->mDesc.mSrgb;
}
GraphicsPipelineDesc deferredPassPipelineSettings = {};
deferredPassPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
deferredPassPipelineSettings.mRenderTargetCount = DEFERRED_RT_COUNT;
deferredPassPipelineSettings.pDepthState = pDepthStateEnable;
deferredPassPipelineSettings.pColorFormats = deferredFormats;
deferredPassPipelineSettings.pSrgbValues = deferredSrgb;
deferredPassPipelineSettings.mSampleCount = pDepthBuffer->mDesc.mSampleCount;
deferredPassPipelineSettings.mSampleQuality = pDepthBuffer->mDesc.mSampleQuality;
deferredPassPipelineSettings.mDepthStencilFormat = pDepthBuffer->mDesc.mFormat;
deferredPassPipelineSettings.pRootSignature = pRootSignatureDeferredPass;
#if !defined(METAL)
deferredPassPipelineSettings.pVertexLayout = &vertexLayout;
#endif
// Create pipelines for geometry sets
for (uint32_t i = 0; i < gNumGeomSets; ++i)
{
#if (MSAASAMPLECOUNT > 1)
deferredPassPipelineSettings.pRasterizerState = i == GEOMSET_ALPHATESTED ? pRasterizerStateCullNoneMS : pRasterizerStateCullFrontMS;
#else
deferredPassPipelineSettings.pRasterizerState = i == GEOMSET_ALPHATESTED ? pRasterizerStateCullNone : pRasterizerStateCullFront;
#endif
deferredPassPipelineSettings.pShaderProgram = pShaderDeferredPass[i];
addPipeline(pRenderer, &deferredPassPipelineSettings, &pPipelineDeferredPass[i]);
}
/************************************************************************/
// Setup the resources needed for the Deferred Shade Pipeline
/************************************************************************/
// Setup pipeline settings
// Create pipeline
// Note: the vertex layout is set to null because the positions of the fullscreen triangle are being calculated automatically
// in the vertex shader using each vertex_id.
GraphicsPipelineDesc deferredShadePipelineSettings = {};
deferredShadePipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
deferredShadePipelineSettings.mRenderTargetCount = 1;
deferredShadePipelineSettings.pDepthState = pDepthStateDisable;
#if (MSAASAMPLECOUNT > 1)
deferredShadePipelineSettings.pRasterizerState = pRasterizerStateCullNoneMS;
#else
deferredShadePipelineSettings.pRasterizerState = pRasterizerStateCullNone;
#endif
deferredShadePipelineSettings.pRootSignature = pRootSignatureDeferredShade;
for (uint32_t i = 0; i < 2; ++i)
{
deferredShadePipelineSettings.pShaderProgram = pShaderDeferredShade[i];
deferredShadePipelineSettings.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
#if (MSAASAMPLECOUNT > 1)
deferredShadePipelineSettings.pColorFormats = &pRenderTargetMSAA->mDesc.mFormat;
deferredShadePipelineSettings.pSrgbValues = &pRenderTargetMSAA->mDesc.mSrgb;
deferredShadePipelineSettings.mSampleQuality = pRenderTargetMSAA->mDesc.mSampleQuality;
#else
//deferredShadePipelineSettings.pColorFormats = &pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mFormat;
deferredShadePipelineSettings.pColorFormats = &pIntermediateRenderTarget->mDesc.mFormat;
deferredShadePipelineSettings.pSrgbValues = &pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSrgb;
deferredShadePipelineSettings.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
#endif
addPipeline(pRenderer, &deferredShadePipelineSettings, &pPipelineDeferredShadeSrgb[i]);
}
/************************************************************************/
// Setup the resources needed for the Deferred Point Light Shade Pipeline
/************************************************************************/
// Create vertex layout
VertexLayout vertexLayoutPointLightShade = {};
vertexLayoutPointLightShade.mAttribCount = 1;
vertexLayoutPointLightShade.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayoutPointLightShade.mAttribs[0].mFormat = ImageFormat::RGBA32F;
vertexLayoutPointLightShade.mAttribs[0].mBinding = 0;
vertexLayoutPointLightShade.mAttribs[0].mLocation = 0;
vertexLayoutPointLightShade.mAttribs[0].mOffset = 0;
// Setup pipeline settings
GraphicsPipelineDesc deferredPointLightPipelineSettings = { 0 };
deferredPointLightPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
deferredPointLightPipelineSettings.mRenderTargetCount = 1;
deferredPointLightPipelineSettings.pBlendState = pBlendStateOneZero;
deferredPointLightPipelineSettings.pDepthState = pDepthStateDisable;
deferredPointLightPipelineSettings.pColorFormats = deferredShadePipelineSettings.pColorFormats;
deferredPointLightPipelineSettings.pSrgbValues = deferredShadePipelineSettings.pSrgbValues;
deferredPointLightPipelineSettings.mSampleCount = deferredShadePipelineSettings.mSampleCount;
deferredPointLightPipelineSettings.pRasterizerState = pRasterizerStateCullBack;
deferredPointLightPipelineSettings.pRootSignature = pRootSignatureDeferredShadePointLight;
deferredPointLightPipelineSettings.pShaderProgram = pShaderDeferredShadePointLight;
deferredPointLightPipelineSettings.pVertexLayout = &vertexLayoutPointLightShade;
addPipeline(pRenderer, &deferredPointLightPipelineSettings, &pPipelineDeferredShadePointLightSrgb);
/************************************************************************/
// Setup HDAO post process pipeline
/************************************************************************/
GraphicsPipelineDesc aoPipelineSettings = {};
aoPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
aoPipelineSettings.mRenderTargetCount = 1;
aoPipelineSettings.pDepthState = pDepthStateDisable;
aoPipelineSettings.pColorFormats = &pRenderTargetAO->mDesc.mFormat;
aoPipelineSettings.pSrgbValues = &pRenderTargetAO->mDesc.mSrgb;
aoPipelineSettings.mSampleCount = pRenderTargetAO->mDesc.mSampleCount;
aoPipelineSettings.mSampleQuality = pRenderTargetAO->mDesc.mSampleQuality;
aoPipelineSettings.pRasterizerState = pRasterizerStateCullNone;
aoPipelineSettings.pRootSignature = pRootSignatureAO;
for (uint32_t i = 0; i < 4; ++i)
{
aoPipelineSettings.pShaderProgram = pShaderAO[i];
addPipeline(pRenderer, &aoPipelineSettings, &pPipelineAO[i]);
}
/************************************************************************/
// Setup Skybox pipeline
/************************************************************************/
//layout and pipeline for skybox draw
VertexLayout vertexLayoutSkybox = {};
vertexLayoutSkybox.mAttribCount = 1;
vertexLayoutSkybox.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayoutSkybox.mAttribs[0].mFormat = ImageFormat::RGBA32F;
vertexLayoutSkybox.mAttribs[0].mBinding = 0;
vertexLayoutSkybox.mAttribs[0].mLocation = 0;
vertexLayoutSkybox.mAttribs[0].mOffset = 0;
GraphicsPipelineDesc pipelineSettings = { 0 };
pipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettings.mRenderTargetCount = 1;
pipelineSettings.pDepthState = NULL;
pipelineSettings.pBlendState = pBlendStateSkyBox;
pipelineSettings.pColorFormats = &pIntermediateRenderTarget->mDesc.mFormat;
pipelineSettings.pSrgbValues = &pIntermediateRenderTarget->mDesc.mSrgb;
pipelineSettings.mSampleCount = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleCount;
pipelineSettings.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
//pipelineSettings.mDepthStencilFormat = pDepthBuffer->mDesc.mFormat;
pipelineSettings.pRootSignature = pRootSingatureSkybox;
pipelineSettings.pShaderProgram = pShaderSkybox;
pipelineSettings.pVertexLayout = &vertexLayoutSkybox;
pipelineSettings.pRasterizerState = pRasterizerStateCullNone;
addPipeline(pRenderer, &pipelineSettings, &pSkyboxPipeline);
/************************************************************************/
// Setup Sun pipeline
/************************************************************************/
//layout and pipeline for skybox draw
VertexLayout vertexLayoutSun = {};
vertexLayoutSun.mAttribCount = 3;
vertexLayoutSun.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayoutSun.mAttribs[0].mFormat = ImageFormat::RGB32F;
vertexLayoutSun.mAttribs[0].mBinding = 0;
vertexLayoutSun.mAttribs[0].mLocation = 0;
vertexLayoutSun.mAttribs[0].mOffset = 0;
vertexLayoutSun.mAttribs[1].mSemantic = SEMANTIC_NORMAL;
vertexLayoutSun.mAttribs[1].mFormat = ImageFormat::RGB32F;
vertexLayoutSun.mAttribs[1].mBinding = 0;
vertexLayoutSun.mAttribs[1].mLocation = 1;
vertexLayoutSun.mAttribs[1].mOffset = sizeof(float3);
vertexLayoutSun.mAttribs[2].mSemantic = SEMANTIC_TEXCOORD0;
vertexLayoutSun.mAttribs[2].mFormat = ImageFormat::RG32F;
vertexLayoutSun.mAttribs[2].mBinding = 0;
vertexLayoutSun.mAttribs[2].mLocation = 2;
vertexLayoutSun.mAttribs[2].mOffset = sizeof(float3) * 2;
//Draw Sun
GraphicsPipelineDesc pipelineSettingsSun = { 0 };
pipelineSettingsSun.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettingsSun.pRasterizerState = pRasterizerStateCullBack;
pipelineSettingsSun.pDepthState = pDepthStateEnable;
pipelineSettingsSun.mDepthStencilFormat = pDepthBuffer->mDesc.mFormat;
pipelineSettingsSun.mRenderTargetCount = 1;
pipelineSettingsSun.pColorFormats = &pRenderTargetSun->mDesc.mFormat;
pipelineSettingsSun.pSrgbValues = &pRenderTargetSun->mDesc.mSrgb;
pipelineSettingsSun.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
pipelineSettingsSun.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
pipelineSettingsSun.pVertexLayout = &vertexLayoutSun;
pipelineSettingsSun.pRootSignature = pRootSigSunPass;
pipelineSettingsSun.pShaderProgram = pSunPass;
addPipeline(pRenderer, &pipelineSettingsSun, &pPipelineSunPass);
/************************************************************************/
// Setup Godray pipeline
/************************************************************************/
VertexLayout vertexLayoutCopyShaders = {};
vertexLayoutCopyShaders.mAttribCount = 0;
GraphicsPipelineDesc pipelineSettingsGodRay = { 0 };
pipelineSettingsGodRay.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettingsGodRay.pRasterizerState = pRasterizerStateCullNone;
pipelineSettingsGodRay.mRenderTargetCount = 1;
pipelineSettingsGodRay.pColorFormats = &pRenderTargetGodRayA->mDesc.mFormat;
pipelineSettingsGodRay.pSrgbValues = &pRenderTargetGodRayA->mDesc.mSrgb;
pipelineSettingsGodRay.mSampleCount = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleCount;
pipelineSettingsGodRay.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
pipelineSettingsGodRay.pVertexLayout = &vertexLayoutCopyShaders;
pipelineSettingsGodRay.pRootSignature = pRootSigGodRayPass;
pipelineSettingsGodRay.pShaderProgram = pGodRayPass;
addPipeline(pRenderer, &pipelineSettingsGodRay, &pPipelineGodRayPass);
/************************************************************************/
// Setup Curve Conversion pipeline
/************************************************************************/
GraphicsPipelineDesc pipelineSettingsCurveConversion = { 0 };
pipelineSettingsCurveConversion.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettingsCurveConversion.pRasterizerState = pRasterizerStateCullNone;
pipelineSettingsCurveConversion.mRenderTargetCount = 1;
pipelineSettingsCurveConversion.pColorFormats = &pCurveConversionRenderTarget->mDesc.mFormat;
pipelineSettingsCurveConversion.pSrgbValues = &pCurveConversionRenderTarget->mDesc.mSrgb;
pipelineSettingsCurveConversion.mSampleCount = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleCount;
pipelineSettingsCurveConversion.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
pipelineSettingsCurveConversion.pVertexLayout = &vertexLayoutCopyShaders;
pipelineSettingsCurveConversion.pRootSignature = pRootSigCurveConversionPass;
pipelineSettingsCurveConversion.pShaderProgram = pShaderCurveConversion;
addPipeline(pRenderer, &pipelineSettingsCurveConversion, &pPipelineCurveConversionPass);
/************************************************************************/
// Setup Present pipeline
/************************************************************************/
GraphicsPipelineDesc pipelineSettingsFinalPass = { 0 };
pipelineSettingsFinalPass.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettingsFinalPass.pRasterizerState = pRasterizerStateCullNone;
pipelineSettingsFinalPass.mRenderTargetCount = 1;
pipelineSettingsFinalPass.pColorFormats = &pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mFormat;
pipelineSettingsFinalPass.pSrgbValues = &pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSrgb;
pipelineSettingsFinalPass.mSampleCount = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleCount;
pipelineSettingsFinalPass.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
pipelineSettingsFinalPass.pVertexLayout = &vertexLayoutCopyShaders;
pipelineSettingsFinalPass.pRootSignature = pRootSigPresentPass;
pipelineSettingsFinalPass.pShaderProgram = pShaderPresentPass;
addPipeline(pRenderer, &pipelineSettingsFinalPass, &pPipelinePresentPass);
return true;
}
void Unload()
{
waitForFences(pGraphicsQueue, gImageCount, pRenderCompleteFences, true);
waitForFences(pComputeQueue, gImageCount, pComputeCompleteFences, true);
// Remove default fences, semaphores
for (uint32_t i = 0; i < gImageCount; ++i)
{
removeFence(pRenderer, pRenderCompleteFences[i]);
removeFence(pRenderer, pComputeCompleteFences[i]);
removeSemaphore(pRenderer, pRenderCompleteSemaphores[i]);
removeSemaphore(pRenderer, pComputeCompleteSemaphores[i]);
}
gAppUI.Unload();
for (uint32_t i = 0; i < 4; ++i)
removePipeline(pRenderer, pPipelineAO[i]);
removePipeline(pRenderer, pPipelineResolve);
removePipeline(pRenderer, pPipelineResolvePost);
removePipeline(pRenderer, pPipelineSunPass);
removePipeline(pRenderer, pPipelineGodRayPass);
removePipeline(pRenderer, pPipelineGodrayResolve);
removePipeline(pRenderer, pPipelineGodrayResolvePost);
removePipeline(pRenderer, pPipelineCurveConversionPass);
removePipeline(pRenderer, pPipelinePresentPass);
// Destroy graphics pipelines
removePipeline(pRenderer, pPipelineDeferredShadePointLightSrgb);
for (uint32_t i = 0; i < 2; ++i)
{
removePipeline(pRenderer, pPipelineDeferredShadeSrgb[i]);
}
for (uint32_t i = 0; i < gNumGeomSets; ++i)
removePipeline(pRenderer, pPipelineDeferredPass[i]);
for (uint32_t i = 0; i < 2; ++i)
{
removePipeline(pRenderer, pPipelineVisibilityBufferShadeSrgb[i]);
}
for (uint32_t i = 0; i < gNumGeomSets; ++i)
removePipeline(pRenderer, pPipelineVisibilityBufferPass[i]);
for (uint32_t i = 0; i < gNumGeomSets; ++i)
removePipeline(pRenderer, pPipelineShadowPass[i]);
removePipeline(pRenderer, pSkyboxPipeline);
removeRenderTargets();
}
void Update(float deltaTime)
{
#if !defined(TARGET_IOS)
if (pSwapChain->mDesc.mEnableVsync != gToggleVSync)
{
waitForFences(pGraphicsQueue, gImageCount, pRenderCompleteFences, true);
::toggleVSync(pRenderer, &pSwapChain);
}
#if !defined(_DURANGO) && !defined(METAL) && !defined(__linux__)
if (gResolutionChange)
{
gResolutionChange = false;
setResolution(getMonitor(0), &gResolutions[gResolutionIndex]);
pVisibilityBuffer->Unload();
pVisibilityBuffer->Load();
}
#endif
#endif
if (gWasColorSpace != gAppSettings.mCurrentSwapChainColorSpace ||
gWasDisplayColorRange != gAppSettings.mDisplayColorRange ||
gWasDisplaySignalRange != gAppSettings.mDisplaySignalRange)
{
#if defined(DIRECT3D12) && !defined(_DURANGO)
if (gWasColorSpace != gAppSettings.mCurrentSwapChainColorSpace && gAppSettings.mOutputMode == OUTPUT_MODE_HDR10)
{
pVisibilityBuffer->Unload();
pVisibilityBuffer->Load();
}
#endif
gWasColorSpace = gAppSettings.mCurrentSwapChainColorSpace;
gWasDisplayColorRange = gAppSettings.mDisplayColorRange;
gWasDisplaySignalRange = gAppSettings.mDisplaySignalRange;
}
//Change swapchain
if (gWasOutputMode != gAppSettings.mOutputMode)
{
waitForFences(pGraphicsQueue, gImageCount, pRenderCompleteFences, false);
#if defined(_DURANGO)
//garuantee that every fence for each index has same value
if (pRenderCompleteFences[0]->mFenceValue == pRenderCompleteFences[1]->mFenceValue &&
pRenderCompleteFences[0]->mFenceValue == pRenderCompleteFences[2]->mFenceValue)
{
#endif
if (gWasOutputMode != OUTPUT_MODE_HDR10)
{
if (gAppSettings.mOutputMode == OUTPUT_MODE_HDR10)
{
pVisibilityBuffer->Unload();
pVisibilityBuffer->Load();
}
}
else if (gWasOutputMode == OUTPUT_MODE_HDR10)
{
pVisibilityBuffer->Unload();
pVisibilityBuffer->Load();
}
gWasOutputMode = gAppSettings.mOutputMode;
#if defined(_DURANGO)
}
#endif
}
// Process user input
handleKeyboardInput(deltaTime);
#if !defined(TARGET_IOS)
pCameraController->update(deltaTime);
#endif
//Camera Walking Update
if (gAppSettings.cameraWalking)
{
if (totalElpasedTime - (0.033333f * gAppSettings.cameraWalkingSpeed) <= cameraWalkingTime)
{
cameraWalkingTime = 0.0f;
}
cameraWalkingTime += deltaTime * gAppSettings.cameraWalkingSpeed;
uint currentCameraFrame = (uint)(cameraWalkingTime / 0.00833f);
float remind = cameraWalkingTime - (float)currentCameraFrame *0.00833f;
float3 newPos = v3ToF3(lerp(f3Tov3(CameraPathData[2 * currentCameraFrame]), f3Tov3(CameraPathData[2 * (currentCameraFrame + 1)]), remind));
pCameraController->moveTo(f3Tov3(newPos));
float3 newLookat = v3ToF3(lerp(f3Tov3(CameraPathData[2 * currentCameraFrame + 1]), f3Tov3(CameraPathData[2 * (currentCameraFrame + 1) + 1]), remind));
pCameraController->lookAt(f3Tov3(newLookat));
}
gAppUI.Update(deltaTime);
updateDynamicUIElements();
}
void Draw()
{
if (!gAppSettings.mAsyncCompute)
{
// Get the current render target for this frame
acquireNextImage(pRenderer, pSwapChain, pImageAcquiredSemaphore, nullptr, &gPresentFrameIdx);
// check to see if we can use the cmd buffer
Fence* pRenderFence = pRenderCompleteFences[gPresentFrameIdx];
FenceStatus fenceStatus;
getFenceStatus(pRenderer, pRenderFence, &fenceStatus);
if (fenceStatus == FENCE_STATUS_INCOMPLETE)
waitForFences(pGraphicsQueue, 1, &pRenderFence, false);
}
else
{
if (gFrameCount < gImageCount)
{
// Set gPresentFrameIdx as gFrameCount
// This gaurantees that every precomputed resources with compute shader have data
gPresentFrameIdx = (uint)gFrameCount;
}
else
{
// Get the current render target for this frame
acquireNextImage(pRenderer, pSwapChain, pImageAcquiredSemaphore, nullptr, &gPresentFrameIdx);
}
// check to see if we can use the cmd buffer
Fence* pComputeFence = pComputeCompleteFences[gPresentFrameIdx];
FenceStatus fenceStatus;
getFenceStatus(pRenderer, pComputeFence, &fenceStatus);
if (fenceStatus == FENCE_STATUS_INCOMPLETE)
waitForFences(pComputeQueue, 1, &pComputeFence, false);
if (gFrameCount >= gImageCount)
{
// check to see if we can use the cmd buffer
Fence* pRenderFence = pRenderCompleteFences[gPresentFrameIdx];
FenceStatus fenceStatus;
getFenceStatus(pRenderer, pRenderFence, &fenceStatus);
if (fenceStatus == FENCE_STATUS_INCOMPLETE)
waitForFences(pGraphicsQueue, 1, &pRenderFence, false);
}
}
updateUniformData(gPresentFrameIdx);
/************************************************************************/
// Compute pass
/************************************************************************/
if (gAppSettings.mAsyncCompute && gAppSettings.mFilterTriangles && !gAppSettings.mHoldFilteredResults)
{
/************************************************************************/
// Update uniform buffer to gpu
/************************************************************************/
BufferUpdateDesc update = { pPerFrameUniformBuffers[gPresentFrameIdx], &gPerFrame[gPresentFrameIdx].gPerFrameUniformData, 0, 0, sizeof(PerFrameConstants) };
updateResource(&update);
/************************************************************************/
// Triangle filtering async compute pass
/************************************************************************/
Cmd* computeCmd = ppComputeCmds[gPresentFrameIdx];
beginCmd(computeCmd);
cmdBeginGpuFrameProfile(computeCmd, pComputeGpuProfiler, true);
triangleFilteringPass(computeCmd, pComputeGpuProfiler, gPresentFrameIdx);
cmdBeginGpuTimestampQuery(computeCmd, pComputeGpuProfiler, "Clear Light Clusters", true);
clearLightClusters(computeCmd, gPresentFrameIdx);
cmdEndGpuTimestampQuery(computeCmd, pComputeGpuProfiler);
if (gAppSettings.mRenderLocalLights)
{
/************************************************************************/
// Synchronization
/************************************************************************/
// Update Light clusters on the GPU
cmdBeginGpuTimestampQuery(computeCmd, pComputeGpuProfiler, "Compute Light Clusters", true);
cmdSynchronizeResources(computeCmd, 1, &pLightClustersCount[gPresentFrameIdx], 0, NULL, false);
computeLightClusters(computeCmd, gPresentFrameIdx);
cmdEndGpuTimestampQuery(computeCmd, pComputeGpuProfiler);
}
cmdEndGpuFrameProfile(computeCmd, pComputeGpuProfiler);
endCmd(computeCmd);
queueSubmit(pComputeQueue, 1, &computeCmd, pComputeCompleteFences[gPresentFrameIdx], 0, NULL, 1, &pComputeCompleteSemaphores[gPresentFrameIdx]);
/************************************************************************/
/************************************************************************/
}
else
{
if (gPresentFrameIdx != -1)
{
BufferUpdateDesc update = { pPerFrameUniformBuffers[gPresentFrameIdx], &gPerFrame[gPresentFrameIdx].gPerFrameUniformData, 0, 0, sizeof(PerFrameConstants) };
updateResource(&update);
}
}
/************************************************************************/
// Draw Pass
/************************************************************************/
if (!gAppSettings.mAsyncCompute || gFrameCount >= gImageCount)
{
Cmd* graphicsCmd = NULL;
pScreenRenderTarget = pIntermediateRenderTarget;
//pScreenRenderTarget = pSwapChain->ppSwapchainRenderTargets[gPresentFrameIdx];
// Get command list to store rendering commands for this frame
graphicsCmd = ppCmds[gPresentFrameIdx];
// Submit all render commands for this frame
beginCmd(graphicsCmd);
cmdBeginGpuFrameProfile(graphicsCmd, pGraphicsGpuProfiler, true);
if (!gAppSettings.mAsyncCompute && gAppSettings.mFilterTriangles && !gAppSettings.mHoldFilteredResults)
{
triangleFilteringPass(graphicsCmd, pGraphicsGpuProfiler, gPresentFrameIdx);
}
if (!gAppSettings.mAsyncCompute || !gAppSettings.mFilterTriangles)
{
cmdBeginGpuTimestampQuery(graphicsCmd, pGraphicsGpuProfiler, "Clear Light Clusters", true);
clearLightClusters(graphicsCmd, gPresentFrameIdx);
cmdEndGpuTimestampQuery(graphicsCmd, pGraphicsGpuProfiler);
}
if ((!gAppSettings.mAsyncCompute || !gAppSettings.mFilterTriangles) && gAppSettings.mRenderLocalLights)
{
// Update Light clusters on the GPU
cmdBeginGpuTimestampQuery(graphicsCmd, pGraphicsGpuProfiler, "Compute Light Clusters", true);
cmdSynchronizeResources(graphicsCmd, 1, &pLightClustersCount[gPresentFrameIdx], 0, NULL, false);
computeLightClusters(graphicsCmd, gPresentFrameIdx);
cmdSynchronizeResources(graphicsCmd, 1, &pLightClusters[gPresentFrameIdx], 0, NULL, false);
cmdEndGpuTimestampQuery(graphicsCmd, pGraphicsGpuProfiler);
}
// Transition swapchain buffer to be used as a render target
TextureBarrier barriers[] = {
{ pScreenRenderTarget->pTexture, RESOURCE_STATE_RENDER_TARGET },
{ pRenderTargetMSAA->pTexture, RESOURCE_STATE_RENDER_TARGET },
{ pDepthBuffer->pTexture, RESOURCE_STATE_DEPTH_WRITE },
};
cmdResourceBarrier(graphicsCmd, 0, NULL, 3, barriers, true);
#ifndef METAL
if (gAppSettings.mFilterTriangles)
{
const uint32_t numBarriers = (gNumGeomSets * gNumViews) + gNumViews + 1 + 2;
uint32_t index = 0;
BufferBarrier barriers2[numBarriers] = {};
for (uint32_t i = 0; i < gNumViews; ++i)
{
barriers2[index++] = { pFilteredIndirectDrawArgumentsBuffer[gPresentFrameIdx][GEOMSET_ALPHATESTED][i], RESOURCE_STATE_INDIRECT_ARGUMENT | RESOURCE_STATE_SHADER_RESOURCE };
barriers2[index++] = { pFilteredIndirectDrawArgumentsBuffer[gPresentFrameIdx][GEOMSET_OPAQUE][i], RESOURCE_STATE_INDIRECT_ARGUMENT | RESOURCE_STATE_SHADER_RESOURCE };
barriers2[index++] = { pFilteredIndexBuffer[gPresentFrameIdx][i], RESOURCE_STATE_INDEX_BUFFER | RESOURCE_STATE_SHADER_RESOURCE };
}
barriers2[index++] = { pFilterIndirectMaterialBuffer[gPresentFrameIdx], RESOURCE_STATE_SHADER_RESOURCE };
barriers2[index++] = { pLightClusters[gPresentFrameIdx], RESOURCE_STATE_SHADER_RESOURCE };
barriers2[index++] = { pLightClustersCount[gPresentFrameIdx], RESOURCE_STATE_SHADER_RESOURCE };
cmdResourceBarrier(graphicsCmd, numBarriers, barriers2, 0, NULL, true);
}
#endif
drawScene(graphicsCmd, gPresentFrameIdx);
drawSkybox(graphicsCmd, gPresentFrameIdx);
#ifdef _DURANGO
// When async compute is on, we need to transition some resources in the graphics queue
// because they can't be transitioned by the compute queue (incompatible)
if (gAppSettings.mAsyncCompute)
setResourcesToComputeCompliantState(gPresentFrameIdx, false);
#else
#ifndef METAL
if (gAppSettings.mFilterTriangles)
{
const uint32_t numBarriers = (gNumGeomSets * gNumViews) + gNumViews + 1 + 2;
uint32_t index = 0;
BufferBarrier barriers2[numBarriers] = {};
for (uint32_t i = 0; i < gNumViews; ++i)
{
barriers2[index++] = { pFilteredIndirectDrawArgumentsBuffer[gPresentFrameIdx][GEOMSET_ALPHATESTED][i], RESOURCE_STATE_UNORDERED_ACCESS };
barriers2[index++] = { pFilteredIndirectDrawArgumentsBuffer[gPresentFrameIdx][GEOMSET_OPAQUE][i], RESOURCE_STATE_UNORDERED_ACCESS };
barriers2[index++] = { pFilteredIndexBuffer[gPresentFrameIdx][i], RESOURCE_STATE_UNORDERED_ACCESS };
}
barriers2[index++] = { pFilterIndirectMaterialBuffer[gPresentFrameIdx], RESOURCE_STATE_UNORDERED_ACCESS };
barriers2[index++] = { pLightClusters[gPresentFrameIdx], RESOURCE_STATE_UNORDERED_ACCESS };
barriers2[index++] = { pLightClustersCount[gPresentFrameIdx], RESOURCE_STATE_UNORDERED_ACCESS };
cmdResourceBarrier(graphicsCmd, numBarriers, barriers2, 0, NULL, true);
}
#endif
#endif
if (gAppSettings.mEnableGodray)
{
drawGodray(graphicsCmd, gPresentFrameIdx);
drawColorconversion(graphicsCmd);
}
cmdBeginGpuTimestampQuery(graphicsCmd, pGraphicsGpuProfiler, "UI Pass", true);
drawGUI(graphicsCmd, gPresentFrameIdx);
cmdEndGpuTimestampQuery(graphicsCmd, pGraphicsGpuProfiler);
presentImage(graphicsCmd, pScreenRenderTarget->pTexture, pSwapChain->ppSwapchainRenderTargets[gPresentFrameIdx]);
cmdEndGpuFrameProfile(graphicsCmd, pGraphicsGpuProfiler);
endCmd(graphicsCmd);
if (gAppSettings.mAsyncCompute)
{
// Submit all the work to the GPU and present
Semaphore* pWaitSemaphores[] = { pImageAcquiredSemaphore, pComputeCompleteSemaphores[gPresentFrameIdx] };
queueSubmit(pGraphicsQueue, 1, &graphicsCmd, pRenderCompleteFences[gPresentFrameIdx], 2, pWaitSemaphores, 1, &pRenderCompleteSemaphores[gPresentFrameIdx]);
}
else
{
queueSubmit(pGraphicsQueue, 1, &graphicsCmd, pRenderCompleteFences[gPresentFrameIdx], 1, &pImageAcquiredSemaphore, 1, &pRenderCompleteSemaphores[gPresentFrameIdx]);
}
Semaphore* pWaitSemaphores[] = { pRenderCompleteSemaphores[gPresentFrameIdx] };
queuePresent(pGraphicsQueue, pSwapChain, gPresentFrameIdx, 1, pWaitSemaphores);
}
++gFrameCount;
}
tinystl::string GetName()
{
return "Visibility Buffer";
}
/************************************************************************/
// Add render targets
/************************************************************************/
bool addRenderTargets()
{
const uint32_t width = mSettings.mWidth;
const uint32_t height = mSettings.mHeight;
SwapChainDesc swapChainDesc = {};
swapChainDesc.pWindow = pWindow;
swapChainDesc.mPresentQueueCount = 1;
swapChainDesc.ppPresentQueues = &pGraphicsQueue;
swapChainDesc.mWidth = width;
swapChainDesc.mHeight = height;
swapChainDesc.mImageCount = gImageCount;
swapChainDesc.mSampleCount = SAMPLE_COUNT_1;
if (gAppSettings.mOutputMode == OUTPUT_MODE_HDR10)
swapChainDesc.mColorFormat = ImageFormat::RGB10A2;
else
swapChainDesc.mColorFormat = ImageFormat::BGRA8;
swapChainDesc.mColorClearValue = { 1, 1, 1, 1 };
swapChainDesc.mSrgb = false;
swapChainDesc.mEnableVsync = false;
addSwapChain(pRenderer, &swapChainDesc, &pSwapChain);
/************************************************************************/
/************************************************************************/
ClearValue optimizedDepthClear = { 1.0f, 0 };
ClearValue optimizedColorClearBlack = { 0.0f, 0.0f, 0.0f, 0.0f };
ClearValue optimizedColorClearWhite = { 1.0f, 1.0f, 1.0f, 1.0f };
BEGINALLOCATION("RTs");
/************************************************************************/
// Main depth buffer
/************************************************************************/
// Add depth buffer
RenderTargetDesc depthRT = {};
depthRT.mArraySize = 1;
depthRT.mClearValue = optimizedDepthClear;
depthRT.mDepth = 1;
depthRT.mFormat = ImageFormat::D32F;
depthRT.mHeight = height;
depthRT.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
depthRT.mSampleQuality = 0;
depthRT.mFlags = TEXTURE_CREATION_FLAG_ESRAM;
depthRT.mWidth = width;
depthRT.pDebugName = L"Depth Buffer RT";
addRenderTarget(pRenderer, &depthRT, &pDepthBuffer);
/************************************************************************/
// Shadow pass render target
/************************************************************************/
RenderTargetDesc shadowRTDesc = {};
shadowRTDesc.mArraySize = 1;
shadowRTDesc.mClearValue = optimizedDepthClear;
shadowRTDesc.mDepth = 1;
shadowRTDesc.mFormat = ImageFormat::D32F;
shadowRTDesc.mWidth = gShadowMapSize;
shadowRTDesc.mSampleCount = SAMPLE_COUNT_1;
shadowRTDesc.mSampleQuality = 0;
//shadowRTDesc.mFlags = TEXTURE_CREATION_FLAG_ESRAM;
shadowRTDesc.mHeight = gShadowMapSize;
shadowRTDesc.pDebugName = L"Shadow Map RT";
addRenderTarget(pRenderer, &shadowRTDesc, &pRenderTargetShadow);
/************************************************************************/
// Visibility buffer pass render target
/************************************************************************/
RenderTargetDesc vbRTDesc = {};
vbRTDesc.mArraySize = 1;
vbRTDesc.mClearValue = optimizedColorClearWhite;
vbRTDesc.mDepth = 1;
vbRTDesc.mFormat = ImageFormat::RGBA8;
vbRTDesc.mHeight = height;
vbRTDesc.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
vbRTDesc.mSampleQuality = 0;
vbRTDesc.mFlags = TEXTURE_CREATION_FLAG_ESRAM;
vbRTDesc.mWidth = width;
vbRTDesc.pDebugName = L"VB RT";
addRenderTarget(pRenderer, &vbRTDesc, &pRenderTargetVBPass);
/************************************************************************/
// Deferred pass render targets
/************************************************************************/
RenderTargetDesc deferredRTDesc = {};
deferredRTDesc.mArraySize = 1;
deferredRTDesc.mClearValue = optimizedColorClearBlack;
deferredRTDesc.mDepth = 1;
deferredRTDesc.mFormat = ImageFormat::RGBA8;
deferredRTDesc.mHeight = height;
deferredRTDesc.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
deferredRTDesc.mSampleQuality = 0;
deferredRTDesc.mWidth = width;
deferredRTDesc.pDebugName = L"G-Buffer RTs";
for (uint32_t i = 0; i < DEFERRED_RT_COUNT; ++i)
{
addRenderTarget(pRenderer, &deferredRTDesc, &pRenderTargetDeferredPass[i]);
}
/************************************************************************/
// MSAA render target
/************************************************************************/
RenderTargetDesc msaaRTDesc = {};
msaaRTDesc.mArraySize = 1;
msaaRTDesc.mClearValue = optimizedColorClearBlack;
msaaRTDesc.mDepth = 1;
msaaRTDesc.mFormat = gAppSettings.mOutputMode == OutputMode::OUTPUT_MODE_SDR ? ImageFormat::RGBA8 : ImageFormat::RGB10A2;
msaaRTDesc.mHeight = height;
msaaRTDesc.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
msaaRTDesc.mSampleQuality = 0;
msaaRTDesc.mWidth = width;
msaaRTDesc.pDebugName = L"MSAA RT";
// Disabling compression data will avoid decompression phase before resolve pass.
// However, the shading pass will require more memory bandwidth.
// We measured with and without compression and without compression is faster in our case.
msaaRTDesc.mFlags = TEXTURE_CREATION_FLAG_NO_COMPRESSION;
addRenderTarget(pRenderer, &msaaRTDesc, &pRenderTargetMSAA);
/************************************************************************/
// HDAO render target
/************************************************************************/
RenderTargetDesc aoRTDesc = {};
aoRTDesc.mArraySize = 1;
aoRTDesc.mClearValue = optimizedColorClearBlack;
aoRTDesc.mDepth = 1;
aoRTDesc.mFormat = ImageFormat::R8;
aoRTDesc.mHeight = height;
aoRTDesc.mSampleCount = SAMPLE_COUNT_1;
aoRTDesc.mSampleQuality = 0;
aoRTDesc.mWidth = width;
aoRTDesc.pDebugName = L"AO RT";
addRenderTarget(pRenderer, &aoRTDesc, &pRenderTargetAO);
/************************************************************************/
// Intermediate render target
/************************************************************************/
RenderTargetDesc postProcRTDesc = {};
postProcRTDesc.mArraySize = 1;
postProcRTDesc.mClearValue = { 0.0f, 0.0f, 0.0f, 0.0f };
postProcRTDesc.mDepth = 1;
postProcRTDesc.mFormat = gAppSettings.mOutputMode == OutputMode::OUTPUT_MODE_SDR ? ImageFormat::RGBA8 : ImageFormat::RGB10A2;
postProcRTDesc.mHeight = mSettings.mHeight;
postProcRTDesc.mWidth = mSettings.mWidth;
postProcRTDesc.mSampleCount = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleCount;
postProcRTDesc.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
postProcRTDesc.pDebugName = L"pIntermediateRenderTarget";
addRenderTarget(pRenderer, &postProcRTDesc, &pIntermediateRenderTarget);
/************************************************************************/
// Setup MSAA resolve pipeline
/************************************************************************/
GraphicsPipelineDesc resolvePipelineSettings = { 0 };
resolvePipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
resolvePipelineSettings.mRenderTargetCount = 1;
resolvePipelineSettings.pDepthState = pDepthStateDisable;
resolvePipelineSettings.pColorFormats = &pIntermediateRenderTarget->mDesc.mFormat;
resolvePipelineSettings.pSrgbValues = &pSwapChain->mDesc.mSrgb;
resolvePipelineSettings.mSampleCount = pSwapChain->mDesc.mSampleCount;
resolvePipelineSettings.mSampleQuality = pSwapChain->mDesc.mSampleQuality;
resolvePipelineSettings.pRasterizerState = pRasterizerStateCullNone;
resolvePipelineSettings.pRootSignature = pRootSignatureResolve;
resolvePipelineSettings.pShaderProgram = pShaderResolve;
addPipeline(pRenderer, &resolvePipelineSettings, &pPipelineResolve);
addPipeline(pRenderer, &resolvePipelineSettings, &pPipelineResolvePost);
/************************************************************************/
// GodRay render target
/************************************************************************/
RenderTargetDesc GRRTDesc = {};
GRRTDesc.mArraySize = 1;
GRRTDesc.mClearValue = { 0.0f, 0.0f, 0.0f, 1.0f };
GRRTDesc.mDepth = 1;
GRRTDesc.mFormat = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mFormat == ImageFormat::BGRA8 ? ImageFormat::RGBA8 : ImageFormat::RGB10A2;
GRRTDesc.mHeight = mSettings.mHeight;
GRRTDesc.mWidth = mSettings.mWidth;
GRRTDesc.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
GRRTDesc.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
GRRTDesc.pDebugName = L"Sun RT";
addRenderTarget(pRenderer, &GRRTDesc, &pRenderTargetSun);
GRRTDesc.mSampleCount = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleCount;
GRRTDesc.pDebugName = L"Sun Resolve RT";
addRenderTarget(pRenderer, &GRRTDesc, &pRenderTargetSunResolved);
GraphicsPipelineDesc resolveGodrayPipelineSettings = { 0 };
resolveGodrayPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
resolveGodrayPipelineSettings.mRenderTargetCount = 1;
resolveGodrayPipelineSettings.pDepthState = pDepthStateDisable;
resolveGodrayPipelineSettings.pColorFormats = &GRRTDesc.mFormat;
resolveGodrayPipelineSettings.pSrgbValues = &pSwapChain->mDesc.mSrgb;
resolveGodrayPipelineSettings.mSampleCount = pSwapChain->mDesc.mSampleCount;
resolveGodrayPipelineSettings.mSampleQuality = pSwapChain->mDesc.mSampleQuality;
resolveGodrayPipelineSettings.pRasterizerState = pRasterizerStateCullNone;
resolveGodrayPipelineSettings.pRootSignature = pRootSignatureGodrayResolve;
resolveGodrayPipelineSettings.pShaderProgram = pShaderGodrayResolve;
addPipeline(pRenderer, &resolveGodrayPipelineSettings, &pPipelineGodrayResolve);
addPipeline(pRenderer, &resolveGodrayPipelineSettings, &pPipelineGodrayResolvePost);
GRRTDesc.mHeight = mSettings.mHeight / gGodrayScale;
GRRTDesc.mWidth = mSettings.mWidth / gGodrayScale;
GRRTDesc.mSampleCount = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleCount;
GRRTDesc.mFormat = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mFormat;
GRRTDesc.pDebugName = L"GodRay RT A";
addRenderTarget(pRenderer, &GRRTDesc, &pRenderTargetGodRayA);
GRRTDesc.pDebugName = L"GodRay RT B";
addRenderTarget(pRenderer, &GRRTDesc, &pRenderTargetGodRayB);
/************************************************************************/
// Color Conversion render target
/************************************************************************/
RenderTargetDesc postCurveConversionRTDesc = {};
postCurveConversionRTDesc.mArraySize = 1;
postCurveConversionRTDesc.mClearValue = { 0.0f, 0.0f, 0.0f, 0.0f };
postCurveConversionRTDesc.mDepth = 1;
postCurveConversionRTDesc.mFormat = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mFormat;
postCurveConversionRTDesc.mHeight = mSettings.mHeight;
postCurveConversionRTDesc.mWidth = mSettings.mWidth;
postCurveConversionRTDesc.mSampleCount = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleCount;
postCurveConversionRTDesc.mSampleQuality = pSwapChain->ppSwapchainRenderTargets[0]->mDesc.mSampleQuality;
postCurveConversionRTDesc.pDebugName = L"pCurveConversionRenderTarget";
addRenderTarget(pRenderer, &postCurveConversionRTDesc, &pCurveConversionRenderTarget);
/************************************************************************/
/************************************************************************/
ENDALLOCATION("RTs");
return true;
}
void removeRenderTargets()
{
removeRenderTarget(pRenderer, pCurveConversionRenderTarget);
removeRenderTarget(pRenderer, pRenderTargetSun);
removeRenderTarget(pRenderer, pRenderTargetSunResolved);
removeRenderTarget(pRenderer, pRenderTargetGodRayA);
removeRenderTarget(pRenderer, pRenderTargetGodRayB);
removeRenderTarget(pRenderer, pIntermediateRenderTarget);
removeRenderTarget(pRenderer, pRenderTargetMSAA);
removeRenderTarget(pRenderer, pRenderTargetAO);
removeRenderTarget(pRenderer, pDepthBuffer);
removeRenderTarget(pRenderer, pRenderTargetVBPass);
removeRenderTarget(pRenderer, pRenderTargetShadow);
for (uint32_t i = 0; i < DEFERRED_RT_COUNT; ++i)
removeRenderTarget(pRenderer, pRenderTargetDeferredPass[i]);
removeSwapChain(pRenderer, pSwapChain);
}
/************************************************************************/
// Load all the shaders needed for the demo
/************************************************************************/
void addShaders()
{
ShaderMacro shadingMacros[2][2] = {
{
{ "SAMPLE_COUNT", tinystl::string::format("%d", MSAASAMPLECOUNT) },
{ "USE_AMBIENT_OCCLUSION", "" }
},
{
{ "SAMPLE_COUNT", tinystl::string::format("%d", MSAASAMPLECOUNT) },
{ "USE_AMBIENT_OCCLUSION", "" }
},
};
ShaderMacro hdaoMacros[4][2] = {};
ShaderLoadDesc shadowPass = {};
ShaderLoadDesc shadowPassAlpha = {};
ShaderLoadDesc vbPass = {};
ShaderLoadDesc vbPassAlpha = {};
ShaderLoadDesc deferredPassAlpha = {};
ShaderLoadDesc deferredPass = {};
ShaderLoadDesc vbShade[2] = {};
ShaderLoadDesc deferredShade[2] = {};
ShaderLoadDesc deferredPointlights = {};
ShaderLoadDesc ao[4] = {};
ShaderLoadDesc resolvePass = {};
ShaderLoadDesc resolveGodrayPass = {};
ShaderLoadDesc clearBuffer = {};
ShaderLoadDesc triangleCulling = {};
#ifndef METAL
ShaderLoadDesc batchCompaction = {};
#endif
ShaderLoadDesc clearLights = {};
ShaderLoadDesc clusterLights = {};
ShaderLoadDesc depthCopyShader = {};
ShaderLoadDesc finalShaderDesc = {};
shadowPass.mStages[0] = { "shadow_pass.vert", NULL, 0, FSR_SrcShaders };
shadowPassAlpha.mStages[0] = { "shadow_pass_alpha.vert", NULL, 0, FSR_SrcShaders };
shadowPassAlpha.mStages[1] = { "shadow_pass_alpha.frag", NULL, 0, FSR_SrcShaders };
vbPass.mStages[0] = { "visibilityBuffer_pass.vert", NULL, 0, FSR_SrcShaders };
vbPass.mStages[1] = { "visibilityBuffer_pass.frag", NULL, 0, FSR_SrcShaders };
vbPassAlpha.mStages[0] = { "visibilityBuffer_pass_alpha.vert", NULL, 0, FSR_SrcShaders };
vbPassAlpha.mStages[1] = { "visibilityBuffer_pass_alpha.frag", NULL, 0, FSR_SrcShaders };
deferredPass.mStages[0] = { "deferred_pass.vert", NULL, 0, FSR_SrcShaders };
deferredPass.mStages[1] = { "deferred_pass.frag", NULL, 0, FSR_SrcShaders };
deferredPassAlpha.mStages[0] = { "deferred_pass.vert", NULL, 0, FSR_SrcShaders };
deferredPassAlpha.mStages[1] = { "deferred_pass_alpha.frag", NULL, 0, FSR_SrcShaders };
for (uint32_t i = 0; i < 2; ++i)
{
shadingMacros[i][1].value = tinystl::string::format("%d", i);//USE_AMBIENT_OCCLUSION
vbShade[i].mStages[0] = { "visibilityBuffer_shade.vert", NULL, 0, FSR_SrcShaders };
vbShade[i].mStages[1] = { "visibilityBuffer_shade.frag", shadingMacros[i], 2, FSR_SrcShaders };
deferredShade[i].mStages[0] = { "deferred_shade.vert", NULL, 0, FSR_SrcShaders };
deferredShade[i].mStages[1] = { "deferred_shade.frag", shadingMacros[i], 2, FSR_SrcShaders };
}
deferredPointlights.mStages[0] = { "deferred_shade_pointlight.vert", shadingMacros[0], 1, FSR_SrcShaders };
deferredPointlights.mStages[1] = { "deferred_shade_pointlight.frag", shadingMacros[0], 1, FSR_SrcShaders };
// Resolve shader
resolvePass.mStages[0] = { "resolve.vert", shadingMacros[0], 1, FSR_SrcShaders };
resolvePass.mStages[1] = { "resolve.frag", shadingMacros[0], 1, FSR_SrcShaders };
// Resolve shader
resolveGodrayPass.mStages[0] = { "resolve.vert", shadingMacros[0], 1, FSR_SrcShaders };
resolveGodrayPass.mStages[1] = { "resolveGodray.frag", shadingMacros[0], 1, FSR_SrcShaders };
// HDAO post-process shader
for (uint32_t i = 0; i < 4; ++i)
{
hdaoMacros[i][0] = shadingMacros[0][0];
hdaoMacros[i][1] = { "AO_QUALITY", tinystl::string::format("%u", (i + 1)) };
ao[i].mStages[0] = { "HDAO.vert", hdaoMacros[i], 2, FSRoot::FSR_SrcShaders };
ao[i].mStages[1] = { "HDAO.frag", hdaoMacros[i], 2, FSRoot::FSR_SrcShaders };
}
// Triangle culling compute shader
triangleCulling.mStages[0] = { "triangle_filtering.comp", 0, NULL, FSRoot::FSR_SrcShaders };
#if !defined(METAL)
// Batch compaction compute shader
batchCompaction.mStages[0] = { "batch_compaction.comp", 0, NULL, FSRoot::FSR_SrcShaders };
#endif
// Clear buffers compute shader
clearBuffer.mStages[0] = { "clear_buffers.comp", 0, NULL, FSRoot::FSR_SrcShaders };
// Clear light clusters compute shader
clearLights.mStages[0] = { "clear_light_clusters.comp", 0, NULL, FSRoot::FSR_SrcShaders };
// Cluster lights compute shader
clusterLights.mStages[0] = { "cluster_lights.comp", 0, NULL, FSRoot::FSR_SrcShaders };
ShaderLoadDesc sunShaderDesc = {};
sunShaderDesc.mStages[0] = { "sun.vert", NULL, 0, FSR_SrcShaders_Common };
sunShaderDesc.mStages[1] = { "sun.frag", NULL, 0, FSR_SrcShaders_Common };
addShader(pRenderer, &sunShaderDesc, &pSunPass);
ShaderLoadDesc godrayShaderDesc = {};
godrayShaderDesc.mStages[0] = { "display.vert", NULL, 0, FSR_SrcShaders_Common };
godrayShaderDesc.mStages[1] = { "godray.frag", NULL, 0, FSR_SrcShaders_Common };
addShader(pRenderer, &godrayShaderDesc, &pGodRayPass);
ShaderLoadDesc CurveConversionShaderDesc = {};
CurveConversionShaderDesc.mStages[0] = { "display.vert", NULL, 0, FSR_SrcShaders_Common };
CurveConversionShaderDesc.mStages[1] = { "CurveConversion.frag", NULL, 0, FSR_SrcShaders_Common };
addShader(pRenderer, &CurveConversionShaderDesc, &pShaderCurveConversion);
ShaderLoadDesc presentShaderDesc = {};
presentShaderDesc.mStages[0] = { "display.vert", NULL, 0, FSR_SrcShaders_Common };
presentShaderDesc.mStages[1] = { "display.frag", NULL, 0, FSR_SrcShaders_Common };
addShader(pRenderer, &presentShaderDesc, &pShaderPresentPass);
addShader(pRenderer, &shadowPass, &pShaderShadowPass[GEOMSET_OPAQUE]);
addShader(pRenderer, &shadowPassAlpha, &pShaderShadowPass[GEOMSET_ALPHATESTED]);
addShader(pRenderer, &vbPass, &pShaderVisibilityBufferPass[GEOMSET_OPAQUE]);
addShader(pRenderer, &vbPassAlpha, &pShaderVisibilityBufferPass[GEOMSET_ALPHATESTED]);
for (uint32_t i = 0; i < 2; ++i)
addShader(pRenderer, &vbShade[i], &pShaderVisibilityBufferShade[i]);
addShader(pRenderer, &deferredPass, &pShaderDeferredPass[GEOMSET_OPAQUE]);
addShader(pRenderer, &deferredPassAlpha, &pShaderDeferredPass[GEOMSET_ALPHATESTED]);
for (uint32_t i = 0; i < 2; ++i)
addShader(pRenderer, &deferredShade[i], &pShaderDeferredShade[i]);
addShader(pRenderer, &deferredPointlights, &pShaderDeferredShadePointLight);
addShader(pRenderer, &clearBuffer, &pShaderClearBuffers);
addShader(pRenderer, &triangleCulling, &pShaderTriangleFiltering);
addShader(pRenderer, &clearLights, &pShaderClearLightClusters);
addShader(pRenderer, &clusterLights, &pShaderClusterLights);
for (uint32_t i = 0; i < 4; ++i)
addShader(pRenderer, &ao[i], &pShaderAO[i]);
addShader(pRenderer, &resolvePass, &pShaderResolve);
addShader(pRenderer, &resolveGodrayPass, &pShaderGodrayResolve);
#ifndef METAL
addShader(pRenderer, &batchCompaction, &pShaderBatchCompaction);
#endif
}
void removeShaders()
{
removeShader(pRenderer, pShaderShadowPass[GEOMSET_OPAQUE]);
removeShader(pRenderer, pShaderShadowPass[GEOMSET_ALPHATESTED]);
removeShader(pRenderer, pShaderVisibilityBufferPass[GEOMSET_OPAQUE]);
removeShader(pRenderer, pShaderVisibilityBufferPass[GEOMSET_ALPHATESTED]);
for (uint32_t i = 0; i < 2; ++i)
removeShader(pRenderer, pShaderVisibilityBufferShade[i]);
removeShader(pRenderer, pShaderDeferredPass[GEOMSET_OPAQUE]);
removeShader(pRenderer, pShaderDeferredPass[GEOMSET_ALPHATESTED]);
for (uint32_t i = 0; i < 2; ++i)
removeShader(pRenderer, pShaderDeferredShade[i]);
removeShader(pRenderer, pShaderDeferredShadePointLight);
removeShader(pRenderer, pShaderTriangleFiltering);
#if !defined(METAL)
removeShader(pRenderer, pShaderBatchCompaction);
#endif
removeShader(pRenderer, pShaderClearBuffers);
removeShader(pRenderer, pShaderClusterLights);
removeShader(pRenderer, pShaderClearLightClusters);
for (uint32_t i = 0; i < 4; ++i)
removeShader(pRenderer, pShaderAO[i]);
removeShader(pRenderer, pShaderResolve);
removeShader(pRenderer, pShaderGodrayResolve);
removeShader(pRenderer, pSunPass);
removeShader(pRenderer, pGodRayPass);
removeShader(pRenderer, pShaderSkybox);
removeShader(pRenderer, pShaderPresentPass);
}
// This method sets the contents of the buffers to indicate the rendering pass that
// the whole scene triangles must be rendered (no cluster / triangle filtering).
// This is useful for testing purposes to compare visual / performance results.
void addTriangleFilteringBuffers()
{
/************************************************************************/
// Material props
/************************************************************************/
uint32_t* alphaTestMaterials = (uint32_t*)conf_malloc(pScene->numMaterials * sizeof(uint32_t));
for (uint32_t i = 0; i < pScene->numMaterials; ++i)
{
alphaTestMaterials[i] = pScene->materials[i].alphaTested ? 1 : 0;
}
BufferLoadDesc materialPropDesc = {};
materialPropDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER;
materialPropDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
materialPropDesc.mDesc.mElementCount = pScene->numMaterials;
materialPropDesc.mDesc.mStructStride = sizeof(uint32_t);
materialPropDesc.mDesc.mSize = materialPropDesc.mDesc.mElementCount * materialPropDesc.mDesc.mStructStride;
materialPropDesc.pData = alphaTestMaterials;
materialPropDesc.ppBuffer = &pMaterialPropertyBuffer;
materialPropDesc.mDesc.pDebugName = L"Material Prop Desc";
addResource(&materialPropDesc);
conf_free(alphaTestMaterials);
/************************************************************************/
// Indirect draw arguments to draw all triangles
/************************************************************************/
#if defined(METAL)
uint32_t bufSize = pScene->numMeshes * sizeof(VisBufferIndirectCommand);
// Set the indirect draw buffer for indirect drawing to the maximum amount of triangles per batch
VisBufferIndirectCommand* indirectDrawArgumentsMax = (VisBufferIndirectCommand*)conf_malloc(bufSize);
memset(indirectDrawArgumentsMax, 0, bufSize);
tinystl::vector<uint32_t> materialIDPerDrawCall(pScene->numMeshes);
for (uint32_t i = 0; i < pScene->numMeshes; i++)
{
VisBufferIndirectCommand* arg = &indirectDrawArgumentsMax[i];
arg->arg.mStartVertex = pScene->meshes[i].startVertex;
arg->arg.mVertexCount = pScene->meshes[i].vertexCount;
arg->arg.mInstanceCount = 1;
arg->arg.mStartInstance = 0;
materialIDPerDrawCall[i] = pScene->meshes[i].materialId;;
}
// Setup uniform data for draw batch data.
BufferLoadDesc indirectBufferDesc = {};
indirectBufferDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_INDIRECT_BUFFER | DESCRIPTOR_TYPE_BUFFER;
indirectBufferDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
indirectBufferDesc.mDesc.mStructStride = sizeof(VisBufferIndirectCommand);
indirectBufferDesc.mDesc.mFirstElement = 0;
indirectBufferDesc.mDesc.mElementCount = pScene->numMeshes;
indirectBufferDesc.mDesc.mSize = indirectBufferDesc.mDesc.mElementCount * indirectBufferDesc.mDesc.mStructStride;
indirectBufferDesc.pData = indirectDrawArgumentsMax;
indirectBufferDesc.ppBuffer = &pIndirectDrawArgumentsBufferAll;
indirectBufferDesc.mDesc.pDebugName = L"Indirect Buffer Desc";
addResource(&indirectBufferDesc);
// Setup indirect material buffer.
BufferLoadDesc indirectDesc = {};
indirectDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER;
indirectDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
indirectDesc.mDesc.mElementCount = pScene->numMeshes;
indirectDesc.mDesc.mStructStride = sizeof(uint32_t);
indirectDesc.mDesc.mSize = indirectDesc.mDesc.mElementCount * indirectDesc.mDesc.mStructStride;
indirectDesc.pData = materialIDPerDrawCall.data();
indirectDesc.ppBuffer = &pIndirectMaterialBufferAll;
indirectDesc.mDesc.pDebugName = L"Indirect Desc";
addResource(&indirectDesc);
conf_free(indirectDrawArgumentsMax);
#else
const uint32_t numBatches = (const uint32_t)pScene->numMeshes;
tinystl::vector<uint32_t> materialIDPerDrawCall(MATERIAL_BUFFER_SIZE);
tinystl::vector<VisBufferIndirectCommand> indirectArgsNoAlpha(MAX_DRAWS_INDIRECT, VisBufferIndirectCommand{ 0 });
tinystl::vector<VisBufferIndirectCommand> indirectArgsAlpha(MAX_DRAWS_INDIRECT, VisBufferIndirectCommand{ 0 });
uint32_t iAlpha = 0, iNoAlpha = 0;
for (uint32_t i = 0; i < numBatches; ++i)
{
uint matID = pScene->meshes[i].materialId;
Material* mat = &pScene->materials[matID];
uint32 numIDX = pScene->meshes[i].indexCount;
uint32 startIDX = pScene->meshes[i].startIndex;
if (mat->alphaTested)
{
#if defined(DIRECT3D12)
indirectArgsAlpha[iAlpha].drawId = iAlpha;
#endif
indirectArgsAlpha[iAlpha].arg.mInstanceCount = 1;
indirectArgsAlpha[iAlpha].arg.mIndexCount = numIDX;
indirectArgsAlpha[iAlpha].arg.mStartIndex = startIDX;
for (uint32_t j = 0; j < gNumViews; ++j)
materialIDPerDrawCall[BaseMaterialBuffer(true, j) + iAlpha] = matID;
iAlpha++;
}
else
{
#if defined(DIRECT3D12)
indirectArgsNoAlpha[iNoAlpha].drawId = iNoAlpha;
#endif
indirectArgsNoAlpha[iNoAlpha].arg.mInstanceCount = 1;
indirectArgsNoAlpha[iNoAlpha].arg.mIndexCount = numIDX;
indirectArgsNoAlpha[iNoAlpha].arg.mStartIndex = startIDX;
for (uint32_t j = 0; j < gNumViews; ++j)
materialIDPerDrawCall[BaseMaterialBuffer(false, j) + iNoAlpha] = matID;
iNoAlpha++;
}
}
*(((UINT*)indirectArgsAlpha.data()) + DRAW_COUNTER_SLOT_POS) = iAlpha;
*(((UINT*)indirectArgsNoAlpha.data()) + DRAW_COUNTER_SLOT_POS) = iNoAlpha;
for (uint32_t frameIdx = 0; frameIdx < gImageCount; ++frameIdx)
{
gPerFrame[frameIdx].gDrawCount[GEOMSET_OPAQUE] = iNoAlpha;
gPerFrame[frameIdx].gDrawCount[GEOMSET_ALPHATESTED] = iAlpha;
}
// DX12 / Vulkan needs two indirect buffers since ExecuteIndirect is not called per mesh but per geometry set (ALPHA_TEST and OPAQUE)
for (uint32_t i = 0; i < gNumGeomSets; ++i)
{
// Setup uniform data for draw batch data
BufferLoadDesc indirectBufferDesc = {};
indirectBufferDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_INDIRECT_BUFFER | DESCRIPTOR_TYPE_BUFFER;
indirectBufferDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
indirectBufferDesc.mDesc.mElementCount = MAX_DRAWS_INDIRECT * (sizeof(VisBufferIndirectCommand) / sizeof(uint32_t));
indirectBufferDesc.mDesc.mStructStride = sizeof(uint32_t);
indirectBufferDesc.mDesc.mSize = indirectBufferDesc.mDesc.mElementCount * indirectBufferDesc.mDesc.mStructStride;
indirectBufferDesc.pData = i == 0 ? indirectArgsNoAlpha.data() : indirectArgsAlpha.data();
indirectBufferDesc.ppBuffer = &pIndirectDrawArgumentsBufferAll[i];
indirectBufferDesc.mDesc.pDebugName = L"Indirect Buffer Desc";
addResource(&indirectBufferDesc);
}
BufferLoadDesc indirectDesc = {};
indirectDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER;
indirectDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
indirectDesc.mDesc.mElementCount = MATERIAL_BUFFER_SIZE;
indirectDesc.mDesc.mStructStride = sizeof(uint32_t);
indirectDesc.mDesc.mSize = indirectDesc.mDesc.mElementCount * indirectDesc.mDesc.mStructStride;
indirectDesc.pData = materialIDPerDrawCall.data();
indirectDesc.ppBuffer = &pIndirectMaterialBufferAll;
indirectDesc.mDesc.pDebugName = L"Indirect Desc";
addResource(&indirectDesc);
#endif
/************************************************************************/
// Indirect buffers for culling
/************************************************************************/
BufferLoadDesc filterIbDesc = {};
filterIbDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_INDEX_BUFFER | DESCRIPTOR_TYPE_BUFFER | DESCRIPTOR_TYPE_RW_BUFFER;
filterIbDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
filterIbDesc.mDesc.mIndexType = INDEX_TYPE_UINT32;
filterIbDesc.mDesc.mElementCount = pScene->totalTriangles * 3;
filterIbDesc.mDesc.mStructStride = sizeof(uint32_t);
filterIbDesc.mDesc.mSize = filterIbDesc.mDesc.mElementCount * filterIbDesc.mDesc.mStructStride;
filterIbDesc.mDesc.pDebugName = L"Filtered IB Desc";
filterIbDesc.pData = NULL;
for (uint32_t i = 0; i < gImageCount; ++i)
{
for (uint32_t j = 0; j < gNumViews; ++j)
{
filterIbDesc.ppBuffer = &pFilteredIndexBuffer[i][j];
addResource(&filterIbDesc);
}
}
#if defined(METAL)
// Set the initial indirect draw buffer contents that won't change here to avoid doing this in the compute shader.
// The filter compute shader will only update mVertexCount accordingly depending on the filtered triangles.
VisBufferIndirectCommand* indirectDrawArguments = (VisBufferIndirectCommand*)conf_malloc(pScene->numMeshes * sizeof(VisBufferIndirectCommand));
for (uint32_t i = 0; i < pScene->numMeshes; i++)
{
indirectDrawArguments[i].arg.mStartVertex = pScene->meshes[i].startVertex;
indirectDrawArguments[i].arg.mVertexCount = 0;
indirectDrawArguments[i].arg.mInstanceCount = 1;
indirectDrawArguments[i].arg.mStartInstance = 0;
}
BufferLoadDesc filterIndirectDesc = {};
filterIndirectDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_INDIRECT_BUFFER | DESCRIPTOR_TYPE_BUFFER | DESCRIPTOR_TYPE_RW_BUFFER;
filterIndirectDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
filterIndirectDesc.mDesc.mElementCount = pScene->numMeshes;
filterIndirectDesc.mDesc.mStructStride = sizeof(VisBufferIndirectCommand);
filterIndirectDesc.mDesc.mSize = filterIndirectDesc.mDesc.mElementCount * filterIndirectDesc.mDesc.mStructStride;
filterIndirectDesc.mDesc.pDebugName = L"Filter Indirect Desc";
filterIndirectDesc.pData = indirectDrawArguments;
for (uint32_t i = 0; i < gImageCount; ++i)
{
for (uint32_t j = 0; j < gNumViews; ++j)
{
filterIndirectDesc.ppBuffer = &pFilteredIndirectDrawArgumentsBuffer[i][j];
addResource(&filterIndirectDesc);
}
}
#else
VisBufferIndirectCommand* indirectDrawArguments = (VisBufferIndirectCommand*)conf_malloc(MAX_DRAWS_INDIRECT * sizeof(VisBufferIndirectCommand));
memset(indirectDrawArguments, 0, MAX_DRAWS_INDIRECT * sizeof(VisBufferIndirectCommand));
for (uint32_t i = 0; i < MAX_DRAWS_INDIRECT; ++i)
{
#if defined(DIRECT3D12)
indirectDrawArguments[i].drawId = i;
#endif
if (i < pScene->numMeshes)
indirectDrawArguments[i].arg.mInstanceCount = 1;
}
BufferLoadDesc filterIndirectDesc = {};
filterIndirectDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_INDIRECT_BUFFER | DESCRIPTOR_TYPE_BUFFER | DESCRIPTOR_TYPE_RW_BUFFER;
filterIndirectDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
filterIndirectDesc.mDesc.mElementCount = MAX_DRAWS_INDIRECT * (sizeof(VisBufferIndirectCommand) / sizeof(uint32_t));
filterIndirectDesc.mDesc.mStructStride = sizeof(uint32_t);
filterIndirectDesc.mDesc.mSize = filterIndirectDesc.mDesc.mElementCount * filterIndirectDesc.mDesc.mStructStride;
filterIndirectDesc.mDesc.pDebugName = L"Filtered Indirect Desc";
filterIndirectDesc.pData = indirectDrawArguments;
BufferLoadDesc uncompactedDesc = {};
uncompactedDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER | DESCRIPTOR_TYPE_RW_BUFFER;
uncompactedDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
uncompactedDesc.mDesc.mElementCount = MAX_DRAWS_INDIRECT;
uncompactedDesc.mDesc.mStructStride = sizeof(UncompactedDrawArguments);
uncompactedDesc.mDesc.mSize = uncompactedDesc.mDesc.mElementCount * uncompactedDesc.mDesc.mStructStride;
uncompactedDesc.mDesc.pDebugName = L"Uncompacted Draw Arguments Desc";
uncompactedDesc.pData = NULL;
BufferLoadDesc filterMaterialDesc = {};
filterMaterialDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER | DESCRIPTOR_TYPE_RW_BUFFER;
filterMaterialDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
filterMaterialDesc.mDesc.mElementCount = MATERIAL_BUFFER_SIZE;
filterMaterialDesc.mDesc.mStructStride = sizeof(uint32_t);
filterMaterialDesc.mDesc.mSize = filterMaterialDesc.mDesc.mElementCount * filterMaterialDesc.mDesc.mStructStride;
filterMaterialDesc.mDesc.pDebugName = L"Filtered Indirect Material Desc";
filterMaterialDesc.pData = NULL;
for (uint32_t i = 0; i < gImageCount; ++i)
{
filterMaterialDesc.ppBuffer = &pFilterIndirectMaterialBuffer[i];
addResource(&filterMaterialDesc);
for (uint32_t view = 0; view < gNumViews; ++view)
{
uncompactedDesc.ppBuffer = &pUncompactedDrawArgumentsBuffer[i][view];
addResource(&uncompactedDesc);
for (uint32_t geom = 0; geom < gNumGeomSets; ++geom)
{
filterIndirectDesc.ppBuffer = &pFilteredIndirectDrawArgumentsBuffer[i][geom][view];
addResource(&filterIndirectDesc);
}
}
}
#endif
conf_free(indirectDrawArguments);
/************************************************************************/
// Triangle filtering buffers
/************************************************************************/
// Create buffers to store the list of filtered triangles. These buffers
// contain the triangle IDs of the triangles that passed the culling tests.
// One buffer per back buffer image is created for triple buffering.
for (uint32_t i = 0; i < gImageCount; ++i)
{
#if defined(METAL)
uint64_t bufferSize = NUM_BATCHES * BATCH_COUNT * sizeof(FilterBatchData);
pFilterBatchChunk[i] = (FilterBatchChunk*)conf_malloc(sizeof(FilterBatchChunk));
pFilterBatchChunk[i]->batches = (FilterBatchData*)conf_malloc(bufferSize);
pFilterBatchChunk[i]->currentBatchCount = 0;
pFilterBatchChunk[i]->currentDrawCallCount = 0;
BufferLoadDesc ubDesc = {};
ubDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_UNIFORM_BUFFER;
ubDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
ubDesc.mDesc.mFlags = BUFFER_CREATION_FLAG_OWN_MEMORY_BIT;
ubDesc.mDesc.mSize = bufferSize;
ubDesc.pData = nullptr;
ubDesc.ppBuffer = &(pFilterBatchChunk[i]->batchDataBuffer);
ubDesc.mDesc.pDebugName = L"Uniform Buffer Desc";
addResource(&ubDesc);
#else
uint32_t bufferSizeTotal = 0;
for (uint32_t j = 0; j < gSmallBatchChunkCount; ++j)
{
const uint32_t bufferSize = BATCH_COUNT * sizeof(FilterBatchData);
bufferSizeTotal += bufferSize;
pFilterBatchChunk[i][j] = (FilterBatchChunk*)conf_malloc(sizeof(FilterBatchChunk));
pFilterBatchChunk[i][j]->batches = (FilterBatchData*)conf_calloc(1, bufferSize);
pFilterBatchChunk[i][j]->currentBatchCount = 0;
pFilterBatchChunk[i][j]->currentDrawCallCount = 0;
}
addUniformRingBuffer(pRenderer, bufferSizeTotal, &pFilterBatchDataBuffer[i]);
#endif
}
#ifndef METAL
/************************************************************************/
// Mesh constants
/************************************************************************/
// create mesh constants buffer
MeshConstants* meshConstants = (MeshConstants*)conf_malloc(pScene->numMeshes * sizeof(MeshConstants));
for (uint32_t i = 0; i < pScene->numMeshes; ++i)
{
meshConstants[i].faceCount = pScene->meshes[i].indexCount / 3;
meshConstants[i].indexOffset = pScene->meshes[i].startIndex;
meshConstants[i].materialID = pScene->meshes[i].materialId;
meshConstants[i].twoSided = pScene->materials[pScene->meshes[i].materialId].twoSided ? 1 : 0;
}
BufferLoadDesc meshConstantDesc = {};
meshConstantDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER;
meshConstantDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
meshConstantDesc.mDesc.mElementCount = pScene->numMeshes;
meshConstantDesc.mDesc.mStructStride = sizeof(MeshConstants);
meshConstantDesc.mDesc.mSize = meshConstantDesc.mDesc.mElementCount * meshConstantDesc.mDesc.mStructStride;
meshConstantDesc.pData = meshConstants;
meshConstantDesc.ppBuffer = &pMeshConstantsBuffer;
meshConstantDesc.mDesc.pDebugName = L"Mesh Constant Desc";
addResource(&meshConstantDesc);
conf_free(meshConstants);
#endif
/************************************************************************/
// Per Frame Constant Buffers
/************************************************************************/
uint64_t size = sizeof(PerFrameConstants);
BufferLoadDesc ubDesc = {};
ubDesc.mDesc.mSize = size;
ubDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_UNIFORM_BUFFER;
ubDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_CPU_TO_GPU;
ubDesc.mDesc.mFlags = BUFFER_CREATION_FLAG_PERSISTENT_MAP_BIT;
ubDesc.pData = nullptr;
ubDesc.mDesc.pDebugName = L"Uniform Buffer Desc";
for (uint32_t i = 0; i < gImageCount; ++i)
{
ubDesc.ppBuffer = &pPerFrameUniformBuffers[i];
addResource(&ubDesc);
}
/************************************************************************/
// Lighting buffers
/************************************************************************/
#if defined(METAL)
// Allocate buffers for per-batch uniform data
gPerBatchUniformBuffers = (Buffer**)conf_malloc(pScene->numMeshes * sizeof(Buffer*));
for (uint32_t j = 0; j < pScene->numMeshes; j++) {
PerBatchConstants perBatchData;
const Material* mat = &pScene->materials[pScene->meshes[j].materialId];
perBatchData.drawId = j;
perBatchData.twoSided = (mat->twoSided ? 1 : 0);
BufferLoadDesc batchUb = {};
batchUb.mDesc.mSize = sizeof(PerBatchConstants);
batchUb.mDesc.mDescriptors = DESCRIPTOR_TYPE_UNIFORM_BUFFER;
batchUb.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
batchUb.pData = &perBatchData;
batchUb.ppBuffer = &gPerBatchUniformBuffers[j];
batchUb.mDesc.pDebugName = L"Batch UB Desc";
addResource(&batchUb);
}
#endif
// Setup lights uniform buffer
for (uint32_t i = 0; i < LIGHT_COUNT; i++)
{
gLightData[i].position.setX(float(rand() % 2000) - 1000.0f);
gLightData[i].position.setY(100);
gLightData[i].position.setZ(float(rand() % 2000) - 1000.0f);
gLightData[i].color.setX(float(rand() % 255) / 255.0f);
gLightData[i].color.setY(float(rand() % 255) / 255.0f);
gLightData[i].color.setZ(float(rand() % 255) / 255.0f);
}
BufferLoadDesc batchUb = {};
batchUb.mDesc.mSize = sizeof(gLightData);
batchUb.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER | DESCRIPTOR_TYPE_UNIFORM_BUFFER;
batchUb.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
batchUb.mDesc.mFirstElement = 0;
batchUb.mDesc.mElementCount = LIGHT_COUNT;
batchUb.mDesc.mStructStride = sizeof(LightData);
batchUb.pData = gLightData;
batchUb.ppBuffer = &pLightsBuffer;
batchUb.mDesc.pDebugName = L"Batch UB Desc";
addResource(&batchUb);
// Setup lights cluster data
uint32_t lightClustersInitData[LIGHT_CLUSTER_WIDTH * LIGHT_CLUSTER_HEIGHT] = {};
BufferLoadDesc lightClustersCountBufferDesc = {};
lightClustersCountBufferDesc.mDesc.mSize = LIGHT_CLUSTER_WIDTH * LIGHT_CLUSTER_HEIGHT * sizeof(uint32_t);
lightClustersCountBufferDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER | DESCRIPTOR_TYPE_RW_BUFFER;
lightClustersCountBufferDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
lightClustersCountBufferDesc.mDesc.mFirstElement = 0;
lightClustersCountBufferDesc.mDesc.mElementCount = LIGHT_CLUSTER_WIDTH * LIGHT_CLUSTER_HEIGHT;
lightClustersCountBufferDesc.mDesc.mStructStride = sizeof(uint32_t);
lightClustersCountBufferDesc.pData = lightClustersInitData;
lightClustersCountBufferDesc.mDesc.pDebugName = L"Light Cluster Count Buffer Desc";
for (uint32_t frameIdx = 0; frameIdx < gImageCount; ++frameIdx)
{
lightClustersCountBufferDesc.ppBuffer = &pLightClustersCount[frameIdx];
addResource(&lightClustersCountBufferDesc);
}
BufferLoadDesc lightClustersDataBufferDesc = {};
lightClustersDataBufferDesc.mDesc.mSize = LIGHT_COUNT * LIGHT_CLUSTER_WIDTH * LIGHT_CLUSTER_HEIGHT * sizeof(uint32_t);
lightClustersDataBufferDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER | DESCRIPTOR_TYPE_RW_BUFFER;
lightClustersDataBufferDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
lightClustersDataBufferDesc.mDesc.mFirstElement = 0;
lightClustersDataBufferDesc.mDesc.mElementCount = LIGHT_COUNT * LIGHT_CLUSTER_WIDTH * LIGHT_CLUSTER_HEIGHT;
lightClustersDataBufferDesc.mDesc.mStructStride = sizeof(uint32_t);
lightClustersDataBufferDesc.pData = nullptr;
lightClustersDataBufferDesc.mDesc.pDebugName = L"Light Cluster Data Buffer Desc";
for (uint32_t frameIdx = 0; frameIdx < gImageCount; ++frameIdx)
{
lightClustersDataBufferDesc.ppBuffer = &pLightClusters[frameIdx];
addResource(&lightClustersDataBufferDesc);
}
/************************************************************************/
/************************************************************************/
}
void removeTriangleFilteringBuffers()
{
/************************************************************************/
// Material props
/************************************************************************/
removeResource(pMaterialPropertyBuffer);
/************************************************************************/
// Indirect draw arguments to draw all triangles
/************************************************************************/
#if defined(METAL)
removeResource(pIndirectDrawArgumentsBufferAll);
removeResource(pIndirectMaterialBufferAll);
#else
// DX12 / Vulkan needs two indirect buffers since ExecuteIndirect is not called per mesh but per geometry set (ALPHA_TEST and OPAQUE)
for (uint32_t i = 0; i < gNumGeomSets; ++i)
{
removeResource(pIndirectDrawArgumentsBufferAll[i]);
}
removeResource(pIndirectMaterialBufferAll);
#endif
/************************************************************************/
// Indirect buffers for culling
/************************************************************************/
for (uint32_t i = 0; i < gImageCount; ++i)
{
for (uint32_t j = 0; j < gNumViews; ++j)
{
removeResource(pFilteredIndexBuffer[i][j]);
}
}
#if defined(METAL)
for (uint32_t i = 0; i < gImageCount; ++i)
{
for (uint32_t view = 0; view < gNumViews; ++view)
{
removeResource(pFilteredIndirectDrawArgumentsBuffer[i][view]);
}
}
#else
for (uint32_t i = 0; i < gImageCount; ++i)
{
removeResource(pFilterIndirectMaterialBuffer[i]);
for (uint32_t view = 0; view < gNumViews; ++view)
{
removeResource(pUncompactedDrawArgumentsBuffer[i][view]);
for (uint32_t geom = 0; geom < gNumGeomSets; ++geom)
{
removeResource(pFilteredIndirectDrawArgumentsBuffer[i][geom][view]);
}
}
}
#endif
/************************************************************************/
// Triangle filtering buffers
/************************************************************************/
// Create buffers to store the list of filtered triangles. These buffers
// contain the triangle IDs of the triangles that passed the culling tests.
// One buffer per back buffer image is created for triple buffering.
for (uint32_t i = 0; i < gImageCount; ++i)
{
#if defined(METAL)
removeResource(pFilterBatchChunk[i]->batchDataBuffer);
conf_free(pFilterBatchChunk[i]->batches);
conf_free(pFilterBatchChunk[i]);
#else
for (uint32_t j = 0; j < gSmallBatchChunkCount; ++j)
{
conf_free(pFilterBatchChunk[i][j]->batches);
conf_free(pFilterBatchChunk[i][j]);
}
removeUniformRingBuffer(pFilterBatchDataBuffer[i]);
#endif
}
#ifndef METAL
/************************************************************************/
// Mesh constants
/************************************************************************/
removeResource(pMeshConstantsBuffer);
#endif
/************************************************************************/
// Per Frame Constant Buffers
/************************************************************************/
for (uint32_t i = 0; i < gImageCount; ++i)
{
removeResource(pPerFrameUniformBuffers[i]);
}
/************************************************************************/
// Lighting buffers
/************************************************************************/
#if defined(METAL)
for (uint32_t j = 0; j < pScene->numMeshes; j++)
{
removeResource(gPerBatchUniformBuffers[j]);
}
conf_free(gPerBatchUniformBuffers);
#endif
removeResource(pLightsBuffer);
for (uint32_t frameIdx = 0; frameIdx < gImageCount; ++frameIdx)
{
removeResource(pLightClustersCount[frameIdx]);
removeResource(pLightClusters[frameIdx]);
}
/************************************************************************/
/************************************************************************/
}
#if !defined(METAL)
void setResourcesToComputeCompliantState(uint32_t frameIdx, bool submitAndWait)
{
if (submitAndWait)
beginCmd(ppCmds[frameIdx]);
BufferBarrier barrier[] = {
{ pVertexBufferPosition, RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE },
{ pIndexBufferAll, RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE },
{ pMeshConstantsBuffer, RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE },
{ pMaterialPropertyBuffer, RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE },
{ pFilterIndirectMaterialBuffer[frameIdx], RESOURCE_STATE_UNORDERED_ACCESS },
{ pUncompactedDrawArgumentsBuffer[frameIdx][VIEW_SHADOW], RESOURCE_STATE_UNORDERED_ACCESS },
{ pUncompactedDrawArgumentsBuffer[frameIdx][VIEW_CAMERA], RESOURCE_STATE_UNORDERED_ACCESS },
{ pLightClustersCount[frameIdx], RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE }
};
cmdResourceBarrier(ppCmds[frameIdx], 8, barrier, 0, NULL, false);
BufferBarrier indirectDrawBarriers[gNumGeomSets*gNumViews] = {};
for (uint32_t i = 0, k = 0; i < gNumGeomSets; i++)
{
for (uint32_t j = 0; j < gNumViews; j++, k++)
{
indirectDrawBarriers[k].pBuffer = pFilteredIndirectDrawArgumentsBuffer[frameIdx][i][j];