Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
5488 lines (4788 sloc) 234 KB
/*
* Copyright (c) 2018-2021 The Forge 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 "../../../Common_3/ThirdParty/OpenSource/EASTL/vector.h"
#include "../../../Common_3/ThirdParty/OpenSource/EASTL/string.h"
#include "../../../Common_3/ThirdParty/OpenSource/EASTL/unordered_map.h"
#include "../../../Common_3/Renderer/IRenderer.h"
#include "../../../Common_3/OS/Interfaces/IProfiler.h"
#include "../../../Common_3/OS/Core/RingBuffer.h"
#include "../../../Common_3/OS/Interfaces/ILog.h"
#include "../../../Common_3/OS/Interfaces/IFileSystem.h"
#include "../../../Common_3/OS/Interfaces/IThread.h"
#include "../../../Common_3/OS/Interfaces/ITime.h"
#include "../../../Common_3/OS/Interfaces/ICameraController.h"
#include "../../../Common_3/OS/Interfaces/IApp.h"
#include "../../../Common_3/OS/Interfaces/IInput.h"
#include "../../../Common_3/OS/Core/ThreadSystem.h"
#include "../../../Middleware_3/UI/AppUI.h"
#include "Geometry.h"
#if defined(XBOX)
#include "../../../Xbox/Common_3/Renderer/Direct3D12/Direct3D12X.h"
#include "../../../Xbox/Common_3/Renderer/IESRAMManager.h"
#define BEGINALLOCATION(X) esramBeginAllocation(pRenderer->pESRAMManager, X, esramGetCurrentOffset(pRenderer->pESRAMManager))
#define ENDALLOCATION(X) esramEndAllocation(pRenderer->pESRAMManager)
#else
#define BEGINALLOCATION(X)
#define ENDALLOCATION(X)
#endif
#include "../../../Common_3/OS/Interfaces/IMemory.h"
#if !defined(METAL)
#define MSAASAMPLECOUNT 2
#else
#define MSAASAMPLECOUNT 1
#endif
ThreadSystem* pThreadSystem;
#define SCENE_SCALE 50.0f
// 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 UniformShadingData
{
float4 lightColor;
uint lightingMode;
uint outputMode;
float4 CameraPlane; //x : near, y : far
};
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 float gCameraWalkingTime = 0.0f;
eastl::vector<float3> gPositionsDirections;
float3 gCameraPathData[29084];
uint gCameraPoints;
float gTotalElpasedTime;
typedef struct VisBufferIndirectCommand
{
#if defined(DIRECT3D12)
// Draw ID is sent as indirect argument through root constant in DX12
uint32_t drawId;
IndirectDrawIndexArguments arg;
uint32_t pad[2];
#else
IndirectDrawIndexArguments arg;
#if !defined(ORBIS)
uint32_t pad[3];
#endif
#endif
} VisBufferIndirectCommand;
/************************************************************************/
// 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;
bool mDrawDebugTargets = false;
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 };
DynamicUIWidgets mDynamicUIWidgetsGR;
GodrayInfo gGodrayInfo;
bool mEnableGodray = true;
uint gGodrayInteration = 3;
float mEsmControl = 80.0f;
float mRetinaScaling = 1.5f;
// HDAO data
DynamicUIWidgets mDynamicUIWidgetsAO;
bool mEnableHDAO = true;
float mRejectRadius = 5.2f;
float mAcceptRadius = 0.12f;
float mAOIntensity = 3.0f;
int mAOQuality = 2;
DynamicUIWidgets 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;
DynamicUIWidgets mLinearScale;
float LinearScale = 140.0f;
// HDR10
DynamicUIWidgets 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;
bool mToggleVSync = false;
} AppSettings;
/************************************************************************/
// Constants
/************************************************************************/
const char* gSceneName = "SanMiguel.gltf";
const char* gSunName = "sun.gltf";
// Number of in-flight buffers
const uint32_t gImageCount = 3;
// Constants
const uint32_t gShadowMapSize = 1024;
const uint32_t gNumViews = NUM_CULLING_VIEWPORTS;
#ifdef METAL
const uint32_t gNumStages = 7;
#else
const uint32_t gNumStages = 3;
#endif
struct UniformDataSkybox
{
mat4 mProjectView;
vec3 mCamPos;
};
const uint32_t gSkyboxSize = 1024;
const uint32_t gSkyboxMips = 9;
struct UniformDataSunMatrices
{
mat4 mProjectView;
mat4 mModelMat;
vec4 mLightColor;
};
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;
/************************************************************************/
// Per frame staging data
/************************************************************************/
struct PerFrameData
{
// Stores the camera/eye position in object space for cluster culling
vec3 gEyeObjectSpace[NUM_CULLING_VIEWPORTS] = {};
PerFrameConstants gPerFrameUniformData = {};
UniformDataSkybox gUniformDataSky;
UniformDataSunMatrices gUniformDataSunMatrices;
GodrayInfo gGodrayInfo;
// These are just used for statistical information
uint32_t gTotalClusters = 0;
uint32_t gCulledClusters = 0;
uint32_t gDrawCount[gNumGeomSets];
uint32_t gTotalDrawCount;
};
/************************************************************************/
// Settings
/************************************************************************/
AppSettings gAppSettings;
/************************************************************************/
// Profiling
/************************************************************************/
ProfileToken gGraphicsProfileToken;
ProfileToken gComputeProfileToken;
/************************************************************************/
// Rendering data
/************************************************************************/
Renderer* pRenderer = NULL;
/************************************************************************/
// Synchronization primitives
/************************************************************************/
Fence* pTransitionFences = NULL;
Fence* pRenderCompleteFences[gImageCount] = { NULL };
Fence* pComputeCompleteFences[gImageCount] = { NULL };
Semaphore* pImageAcquiredSemaphore = NULL;
Semaphore* pRenderCompleteSemaphores[gImageCount] = { NULL };
Semaphore* pComputeCompleteSemaphores[gImageCount] = { NULL };
/************************************************************************/
// Queues and Command buffers
/************************************************************************/
Queue* pGraphicsQueue = NULL;
CmdPool* pCmdPool[gImageCount] = { NULL };
Cmd* ppCmds[gImageCount] = { NULL };
Queue* pComputeQueue = NULL;
CmdPool* pComputeCmdPool[gImageCount] = { NULL };
Cmd* ppComputeCmds[gImageCount] = { NULL };
/************************************************************************/
// Swapchain
/************************************************************************/
SwapChain* pSwapChain = NULL;
/************************************************************************/
// Clear buffers pipeline
/************************************************************************/
Shader* pShaderClearBuffers = nullptr;
Pipeline* pPipelineClearBuffers = nullptr;
/************************************************************************/
// Triangle filtering pipeline
/************************************************************************/
Shader* pShaderTriangleFiltering = nullptr;
Pipeline* pPipelineTriangleFiltering = nullptr;
RootSignature* pRootSignatureTriangleFiltering = nullptr;
DescriptorSet* pDescriptorSetTriangleFiltering[2] = { NULL };
/************************************************************************/
// Batch compaction pipeline
/************************************************************************/
Shader* pShaderBatchCompaction = nullptr;
Pipeline* pPipelineBatchCompaction = nullptr;
#if defined(METAL)
// Metal ICB
Shader* pShaderICBGenerator = nullptr;
Pipeline* pPipelineICBGenerator = nullptr;
#endif
/************************************************************************/
// Clear light clusters pipeline
/************************************************************************/
Shader* pShaderClearLightClusters = nullptr;
Pipeline* pPipelineClearLightClusters = nullptr;
RootSignature* pRootSignatureLightClusters = nullptr;
DescriptorSet* pDescriptorSetLightClusters[2] = { NULL };
/************************************************************************/
// Compute light clusters pipeline
/************************************************************************/
Shader* pShaderClusterLights = nullptr;
Pipeline* pPipelineClusterLights = nullptr;
/************************************************************************/
// Shadow pass pipeline
/************************************************************************/
Shader* pShaderShadowPass[gNumGeomSets] = { NULL };
Pipeline* pPipelineShadowPass[gNumGeomSets] = { NULL };
/************************************************************************/
// VB pass pipeline
/************************************************************************/
Shader* pShaderVisibilityBufferPass[gNumGeomSets] = {};
Pipeline* pPipelineVisibilityBufferPass[gNumGeomSets] = {};
RootSignature* pRootSignatureVBPass = nullptr;
CommandSignature* pCmdSignatureVBPass = nullptr;
#if !defined(METAL)
DescriptorSet* pDescriptorSetVBPass[2] = { NULL };
#endif
/************************************************************************/
// VB shade pipeline
/************************************************************************/
Shader* pShaderVisibilityBufferShade[2] = { nullptr };
Pipeline* pPipelineVisibilityBufferShadeSrgb[2] = { nullptr };
RootSignature* pRootSignatureVBShade = nullptr;
DescriptorSet* pDescriptorSetVBShade[2] = { NULL };
/************************************************************************/
// Deferred pass pipeline
/************************************************************************/
Shader* pShaderDeferredPass[gNumGeomSets] = {};
Pipeline* pPipelineDeferredPass[gNumGeomSets] = {};
RootSignature* pRootSignatureDeferredPass = nullptr;
CommandSignature* pCmdSignatureDeferredPass = nullptr;
DescriptorSet* pDescriptorSetDeferredPass[2] = { NULL };
/************************************************************************/
// Deferred shade pipeline
/************************************************************************/
Shader* pShaderDeferredShade[2] = { nullptr };
Pipeline* pPipelineDeferredShadeSrgb[2] = { nullptr };
RootSignature* pRootSignatureDeferredShade = nullptr;
DescriptorSet* pDescriptorSetDeferredShade[2] = { NULL };
/************************************************************************/
// Deferred point light shade pipeline
/************************************************************************/
Shader* pShaderDeferredShadePointLight = nullptr;
Pipeline* pPipelineDeferredShadePointLightSrgb = nullptr;
RootSignature* pRootSignatureDeferredShadePointLight = nullptr;
DescriptorSet* pDescriptorSetDeferredShadePointLight[2] = { NULL };
/************************************************************************/
// AO pipeline
/************************************************************************/
Shader* pShaderAO[4] = { nullptr };
Pipeline* pPipelineAO[4] = { nullptr };
RootSignature* pRootSignatureAO = nullptr;
DescriptorSet* pDescriptorSetAO = { NULL };
/************************************************************************/
// Resolve pipeline
/************************************************************************/
Shader* pShaderResolve = nullptr;
Pipeline* pPipelineResolve = nullptr;
Pipeline* pPipelineResolvePost = nullptr;
RootSignature* pRootSignatureResolve = nullptr;
DescriptorSet* pDescriptorSetResolve = { NULL };
Shader* pShaderGodrayResolve = nullptr;
Pipeline* pPipelineGodrayResolve = nullptr;
Pipeline* pPipelineGodrayResolvePost = nullptr;
/************************************************************************/
// Skybox pipeline
/************************************************************************/
Shader* pShaderSkybox = nullptr;
Pipeline* pSkyboxPipeline = nullptr;
RootSignature* pRootSingatureSkybox = nullptr;
Buffer* pSkyboxVertexBuffer = NULL;
Texture* pSkybox = NULL;
DescriptorSet* pDescriptorSetSkybox[2] = { NULL };
/************************************************************************/
// Godray pipeline
/************************************************************************/
Shader* pSunPass = nullptr;
Pipeline* pPipelineSunPass = nullptr;
RootSignature* pRootSigSunPass = nullptr;
DescriptorSet* pDescriptorSetSunPass = { NULL };
VertexLayout gVertexLayoutSun = {};
Shader* pGodRayPass = nullptr;
Pipeline* pPipelineGodRayPass = nullptr;
RootSignature* pRootSigGodRayPass = nullptr;
DescriptorSet* pDescriptorSetGodRayPass = NULL;
#if defined(METAL)
DescriptorSet* pDescriptorSetGodRayPassSampler = NULL;
#endif
Geometry* pSun = NULL;
/************************************************************************/
// Curve Conversion pipeline
/************************************************************************/
Shader* pShaderCurveConversion = nullptr;
Pipeline* pPipelineCurveConversionPass = nullptr;
RootSignature* pRootSigCurveConversionPass = nullptr;
DescriptorSet* pDescriptorSetCurveConversionPass = NULL;
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;
DescriptorSet* pDescriptorSetPresentPass = { NULL };
/************************************************************************/
// Render targets
/************************************************************************/
RenderTarget* pDepthBuffer = NULL;
RenderTarget* pRenderTargetVBPass = NULL;
RenderTarget* pRenderTargetMSAA = NULL;
RenderTarget* pRenderTargetDeferredPass[DEFERRED_RT_COUNT] = { NULL };
RenderTarget* pRenderTargetShadow = NULL;
RenderTarget* pRenderTargetAO = NULL;
RenderTarget* pIntermediateRenderTarget = NULL;
RenderTarget* pRenderTargetSun = NULL;
RenderTarget* pRenderTargetSunResolved = NULL;
RenderTarget* pRenderTargetGodRay[2] = { NULL };
RenderTarget* pCurveConversionRenderTarget = NULL;
/************************************************************************/
// Samplers
/************************************************************************/
Sampler* pSamplerTrilinearAniso = NULL;
Sampler* pSamplerBilinear = NULL;
Sampler* pSamplerPointClamp = NULL;
Sampler* pSamplerBilinearClamp = NULL;
/************************************************************************/
// Bindless texture array
/************************************************************************/
Texture* gDiffuseMapsStorage = NULL;
Texture* gNormalMapsStorage = NULL;
Texture* gSpecularMapsStorage = NULL;
eastl::vector<Texture*> gDiffuseMaps;
eastl::vector<Texture*> gNormalMaps;
eastl::vector<Texture*> gSpecularMaps;
eastl::vector<Texture*> gDiffuseMapsPacked;
eastl::vector<Texture*> gNormalMapsPacked;
eastl::vector<Texture*> gSpecularMapsPacked;
/************************************************************************/
// Vertex buffers for the scene
/************************************************************************/
Geometry* pGeom = NULL;
/************************************************************************/
// Indirect buffers
/************************************************************************/
Buffer* pMaterialPropertyBuffer = NULL;
Buffer* pPerFrameUniformBuffers[gImageCount] = { NULL };
// Buffers containing all indirect draw commands per geometry set (no culling)
Buffer* pIndirectDrawArgumentsBufferAll[gNumGeomSets] = { NULL };
Buffer* pIndirectMaterialBufferAll = NULL;
Buffer* pMeshConstantsBuffer = NULL;
// Buffers containing filtered indirect draw commands per geometry set (culled)
Buffer* pFilteredIndirectDrawArgumentsBuffer[gImageCount][gNumGeomSets][gNumViews] = { { { NULL } } };
// Buffer containing the draw args after triangle culling which will be stored compactly in the indirect buffer
Buffer* pUncompactedDrawArgumentsBuffer[gImageCount][gNumViews] = { { NULL } };
Buffer* pFilterIndirectMaterialBuffer[gImageCount] = { NULL };
/************************************************************************/
// Index buffers
/************************************************************************/
Buffer* pFilteredIndexBuffer[gImageCount][gNumViews] = {};
/************************************************************************/
// Other buffers for lighting, point lights,...
/************************************************************************/
Buffer* pLightsBuffer = NULL;
Buffer** gPerBatchUniformBuffers = NULL;
Buffer* pVertexBufferCube = NULL;
Buffer* pIndexBufferCube = NULL;
Buffer* pLightClustersCount[gImageCount] = { NULL };
Buffer* pLightClusters[gImageCount] = { NULL };
Buffer* pUniformBufferSun[gImageCount] = { NULL };
Buffer* pUniformBufferSky[gImageCount] = { NULL };
uint64_t gFrameCount = 0;
ClusterContainer* pMeshes = NULL;
uint32_t gMeshCount = 0;
uint32_t gMaterialCount = 0;
UIApp gAppUI;
GuiComponent* pGuiWindow = NULL;
GuiComponent* pDebugTexturesWindow = NULL;
TextDrawDesc gFrameTimeDraw = TextDrawDesc(0, 0xff00ffff, 18);
/************************************************************************/
// Metal ICB
/************************************************************************/
#if defined(METAL)
Buffer* pIndirectCommandBufferShadow[gImageCount] = { NULL };
Buffer* pIndirectCommandBufferCamera[gImageCount] = { NULL };
Buffer* pDrawIDBuffer = { NULL }; // temporary DrawId buffer to pass to ICB
CommandSignature* pCmdSignatureICBOptimize = NULL;
#endif
/************************************************************************/
// Triangle filtering data
/************************************************************************/
const uint32_t gSmallBatchChunkCount = max(1U, 512U / CLUSTER_SIZE) * 16U;
FilterBatchChunk* pFilterBatchChunk[gImageCount][gSmallBatchChunkCount] = { { NULL } };
GPURingBuffer* pFilterBatchDataBuffer = { NULL };
/************************************************************************/
ICameraController* pCameraController = NULL;
/************************************************************************/
// CPU staging data
/************************************************************************/
// CPU buffers for light data
LightData gLightData[LIGHT_COUNT] = {};
PerFrameData gPerFrame[gImageCount] = {};
RenderTarget* pScreenRenderTarget = NULL;
/************************************************************************/
// Screen resolution UI data
/************************************************************************/
#if defined(_WINDOWS)
IWidget* gResolutionProperty = NULL;
eastl::vector<Resolution> gResolutions;
uint32_t gResolutionIndex = 0;
bool gResolutionChange = false;
struct ResolutionData
{
eastl::vector<eastl::string> resNameContainer;
eastl::vector<const char*> resNamePointers;
eastl::vector<uint32_t> resValues;
};
static ResolutionData gGuiResolution;
#endif
const char* pPipelineCacheName = "PipelineCache.cache";
PipelineCache* pPipelineCache = NULL;
/************************************************************************/
/************************************************************************/
class VisibilityBuffer* pVisibilityBuffer = NULL;
/************************************************************************/
// Culling intrinsic data
/************************************************************************/
const uint32_t pdep_lut[8] = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15 };
/************************************************************************/
// App implementation
/************************************************************************/
void SetupDebugTexturesWindow()
{
float scale = 0.15f;
float2 screenSize = { (float)pRenderTargetVBPass->mWidth, (float)pRenderTargetVBPass->mHeight };
float2 texSize = screenSize * scale;
if (!pDebugTexturesWindow)
{
GuiDesc guiDesc = {};
guiDesc.mStartSize = vec2(guiDesc.mStartSize.getX(), guiDesc.mStartSize.getY());
guiDesc.mStartPosition.setY(screenSize.getY() - texSize.getY() - 50.f);
pDebugTexturesWindow = gAppUI.AddGuiComponent("DEBUG RTs", &guiDesc);
ASSERT(pDebugTexturesWindow);
pDebugTexturesWindow->AddWidget(DebugTexturesWidget("Debug RTs"));
}
eastl::vector<Texture*> pVBRTs;
#if (MSAASAMPLECOUNT == 1)
if (gAppSettings.mRenderMode == RENDERMODE_VISBUFF)
{
pVBRTs.push_back(pRenderTargetVBPass->pTexture);
}
else
{
pVBRTs.push_back(pRenderTargetDeferredPass[0]->pTexture);
pVBRTs.push_back(pRenderTargetDeferredPass[1]->pTexture);
pVBRTs.push_back(pRenderTargetDeferredPass[2]->pTexture);
pVBRTs.push_back(pRenderTargetDeferredPass[3]->pTexture);
}
#endif
pVBRTs.push_back(pRenderTargetAO->pTexture);
pVBRTs.push_back(pRenderTargetShadow->pTexture);
((DebugTexturesWidget*)pDebugTexturesWindow->mWidgets[0])->SetTextures(pVBRTs, texSize);
}
IWidget* addResolutionProperty(
GuiComponent* pUIManager, uint32_t& resolutionIndex, uint32_t resCount, Resolution* pResolutions, WidgetCallback onResolutionChanged)
{
#if defined(_WINDOWS)
if (pUIManager)
{
ResolutionData& data = gGuiResolution;
data.resNameContainer.clear();
data.resNamePointers.clear();
data.resValues.clear();
for (uint32_t i = 0; i < resCount; ++i)
{
data.resNameContainer.push_back(eastl::string().sprintf("%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].c_str();
}
data.resNamePointers[data.resNamePointers.size() - 1] = NULL;
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;
}
bool gTestGraphicsReset = false;
void testGraphicsReset()
{
gTestGraphicsReset = !gTestGraphicsReset;
}
class VisibilityBuffer : public IApp
{
public:
#if defined(DIRECT3D12)
void SetHDRMetaData(float MaxOutputNits, float MinOutputNits, float MaxCLL, float MaxFALL)
{
#if !defined(XBOX)
// 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()
{
// FILE PATHS
fsSetPathForResourceDir(pSystemFileIO, RM_CONTENT, RD_SHADER_SOURCES, "Shaders");
fsSetPathForResourceDir(pSystemFileIO, RM_DEBUG, RD_SHADER_BINARIES, "CompiledShaders");
fsSetPathForResourceDir(pSystemFileIO, RM_DEBUG, RD_PIPELINE_CACHE, "PipelineCaches");
fsSetPathForResourceDir(pSystemFileIO, RM_CONTENT, RD_GPU_CONFIG, "GPUCfg");
fsSetPathForResourceDir(pSystemFileIO, RM_CONTENT, RD_TEXTURES, "Textures");
fsSetPathForResourceDir(pSystemFileIO, RM_CONTENT, RD_FONTS, "Fonts");
fsSetPathForResourceDir(pSystemFileIO, RM_CONTENT, RD_MESHES, "Meshes");
fsSetPathForResourceDir(pSystemFileIO, RM_CONTENT, RD_OTHER_FILES, "");
initThreadSystem(&pThreadSystem);
pVisibilityBuffer = this;
// Camera Walking
FileStream fh = {};
if (fsOpenStreamFromPath(RD_OTHER_FILES, "cameraPath.bin", FM_READ_BINARY, &fh))
{
fsReadFromStream(&fh, gCameraPathData, sizeof(float3) * 29084);
fsCloseStream(&fh);
}
gCameraPoints = (uint)29084 / 2;
gTotalElpasedTime = (float)gCameraPoints * 0.00833f;
#if defined(_WINDOWS)
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
/************************************************************************/
// 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);
if (!initInputSystem(pWindow))
return false;
// Microprofiler Actions
InputActionDesc actionDesc = { InputBindings::BUTTON_FULLSCREEN, [](InputActionContext* ctx) { toggleFullscreen(((IApp*)ctx->pUserData)->pWindow); return true; }, this };
addInputAction(&actionDesc);
actionDesc = { InputBindings::BUTTON_EXIT, [](InputActionContext* ctx) { requestShutdown(); return true; } };
addInputAction(&actionDesc);
actionDesc =
{
InputBindings::BUTTON_ANY, [](InputActionContext* ctx)
{
bool capture = gAppUI.OnButton(ctx->mBinding, ctx->mBool, ctx->pPosition);
setEnableCaptureInput(capture && INPUT_ACTION_PHASE_CANCELED != ctx->mPhase);
return true;
}, this
};
addInputAction(&actionDesc);
typedef bool (*CameraInputHandler)(InputActionContext* ctx, uint32_t index);
static CameraInputHandler onCameraInput = [](InputActionContext* ctx, uint32_t index)
{
if (!gAppUI.IsFocused() && *ctx->pCaptured)
index ? pCameraController->onRotate(ctx->mFloat2) : pCameraController->onMove(ctx->mFloat2);
return true;
};
actionDesc = { InputBindings::FLOAT_RIGHTSTICK, [](InputActionContext* ctx) { return onCameraInput(ctx, 1); }, NULL, 20.0f, 200.0f, 1.0f };
addInputAction(&actionDesc);
actionDesc = { InputBindings::FLOAT_LEFTSTICK, [](InputActionContext* ctx) { return onCameraInput(ctx, 0); }, NULL, 20.0f, 200.0f, 1.0f };
addInputAction(&actionDesc);
actionDesc = { InputBindings::BUTTON_NORTH, [](InputActionContext* ctx) { pCameraController->resetView(); return true; } };
addInputAction(&actionDesc);
return true;
}
void Exit()
{
exitInputSystem();
shutdownThreadSystem(pThreadSystem);
destroyCameraController(pCameraController);
}
// 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()
{
if (mSettings.mResetGraphics || !pRenderer)
{
/************************************************************************/
// Initialize the Forge renderer with the appropriate parameters.
/************************************************************************/
RendererDesc settings = {};
initRenderer(GetName(), &settings, &pRenderer);
//check for init success
if (!pRenderer)
return false;
QueueDesc queueDesc = {};
queueDesc.mType = QUEUE_TYPE_GRAPHICS;
queueDesc.mFlag = QUEUE_FLAG_INIT_MICROPROFILE;
addQueue(pRenderer, &queueDesc, &pGraphicsQueue);
QueueDesc computeQueueDesc = {};
computeQueueDesc.mType = QUEUE_TYPE_COMPUTE;
computeQueueDesc.mFlag = QUEUE_FLAG_INIT_MICROPROFILE;
addQueue(pRenderer, &computeQueueDesc, &pComputeQueue);
addFence(pRenderer, &pTransitionFences);
addSemaphore(pRenderer, &pImageAcquiredSemaphore);
for (uint32_t i = 0; i < gImageCount; ++i)
{
// 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.
CmdPoolDesc cmdPoolDesc = {};
cmdPoolDesc.pQueue = pGraphicsQueue;
addCmdPool(pRenderer, &cmdPoolDesc, &pCmdPool[i]);
CmdDesc cmdDesc = {};
cmdDesc.pPool = pCmdPool[i];
addCmd(pRenderer, &cmdDesc, &ppCmds[i]);
// 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.
cmdPoolDesc.pQueue = pComputeQueue;
addCmdPool(pRenderer, &cmdPoolDesc, &pComputeCmdPool[i]);
cmdDesc.pPool = pComputeCmdPool[i];
addCmd(pRenderer, &cmdDesc, &ppComputeCmds[i]);
}
/************************************************************************/
// Initialize helper interfaces (resource loader, profiler)
/************************************************************************/
initResourceLoaderInterface(pRenderer);
PipelineCacheLoadDesc cacheDesc = {};
cacheDesc.pFileName = pPipelineCacheName;
addPipelineCache(pRenderer, &cacheDesc, &pPipelineCache);
/************************************************************************/
// Setup the UI components for text rendering, UI controls...
/************************************************************************/
if (!gAppUI.Init(pRenderer))
return false;
gAppUI.LoadFont("TitilliumText/TitilliumText-Bold.otf");
initProfiler();
initProfilerUI(&gAppUI, mSettings.mWidth, mSettings.mHeight);
gGraphicsProfileToken = addGpuProfiler(pRenderer, pGraphicsQueue, "Graphics");
gComputeProfileToken = addGpuProfiler(pRenderer, pComputeQueue, "Compute");
/************************************************************************/
// Start timing the scene load
/************************************************************************/
HiresTimer timer;
// Load shaders
addShaders();
HiresTimer shaderTimer;
LOGF(LogLevel::eINFO, "Load shaders : %f ms", shaderTimer.GetUSec(true) / 1000.0f);
/************************************************************************/
// Setup sampler states
/************************************************************************/
// 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
/************************************************************************/
addThreadSystemTask(pThreadSystem, memberTaskFunc0<VisibilityBuffer, &VisibilityBuffer::LoadSkybox>, this);
/************************************************************************/
// Load the scene using the SceneLoader class
/************************************************************************/
HiresTimer sceneLoadTimer;
Scene* pScene = loadScene(gSceneName, 50.0f, -20.0f, 0.0f, 0.0f);
if (!pScene)
return false;
LOGF(LogLevel::eINFO, "Load scene : %f ms", sceneLoadTimer.GetUSec(true) / 1000.0f);
gMeshCount = pScene->geom->mDrawArgCount;
gMaterialCount = pScene->geom->mDrawArgCount;
pMeshes = (ClusterContainer*)tf_malloc(gMeshCount * sizeof(ClusterContainer));
pGeom = pScene->geom;
/************************************************************************/
// Texture loading
/************************************************************************/
gDiffuseMaps.resize(gMaterialCount);
gNormalMaps.resize(gMaterialCount);
gSpecularMaps.resize(gMaterialCount);
for (uint32_t i = 0; i < (uint32_t)gDiffuseMaps.size(); ++i)
{
TextureLoadDesc desc = {};
desc.pFileName = pScene->textures[i];
desc.ppTexture = &gDiffuseMaps[i];
addResource(&desc, NULL);
desc.pFileName = pScene->normalMaps[i];
desc.ppTexture = &gNormalMaps[i];
addResource(&desc, NULL);
desc.pFileName = pScene->specularMaps[i];
desc.ppTexture = &gSpecularMaps[i];
addResource(&desc, NULL);
}
/************************************************************************/
// Cluster creation
/************************************************************************/
HiresTimer clusterTimer;
// Calculate clusters
for (uint32_t i = 0; i < gMeshCount; ++i)
{
ClusterContainer* mesh = pMeshes + i;
Material* material = pScene->materials + i;
createClusters(material->twoSided, pScene, pScene->geom->pDrawArgs + i, mesh);
}
tf_free(pScene->geom->pShadow);
LOGF(LogLevel::eINFO, "Load clusters : %f ms", clusterTimer.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 = gMaterialCount;
vbRootDesc.ppStaticSamplerNames = &pTextureSamplerName;
vbRootDesc.ppStaticSamplers = &pSamplerPointClamp;
vbRootDesc.mStaticSamplerCount = 1;
addRootSignature(pRenderer, &vbRootDesc, &pRootSignatureVBPass);
RootSignatureDesc deferredPassRootDesc = { pShaderDeferredPass, gNumGeomSets };
deferredPassRootDesc.mMaxBindlessTextures = gMaterialCount;
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 = gMaterialCount;
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);
// Triangle filtering root signatures
#if defined(METAL)
Shader* pCullingShaders[] = { pShaderClearBuffers, pShaderTriangleFiltering, pShaderBatchCompaction, pShaderICBGenerator };
#else
Shader* pCullingShaders[] = { pShaderClearBuffers, pShaderTriangleFiltering, pShaderBatchCompaction };
#endif
RootSignatureDesc triangleFilteringRootDesc = { pCullingShaders, sizeof(pCullingShaders) / sizeof(pCullingShaders[0]) };
addRootSignature(pRenderer, &triangleFilteringRootDesc, &pRootSignatureTriangleFiltering);
Shader* pClusterShaders[] = { pShaderClearLightClusters, pShaderClusterLights };
RootSignatureDesc clearLightRootDesc = { pClusterShaders, 2 };
addRootSignature(pRenderer, &clearLightRootDesc, &pRootSignatureLightClusters);
const char* pColorConvertStaticSamplerNames[] = { "uSampler0" };
RootSignatureDesc CurveConversionRootSigDesc = { &pShaderCurveConversion, 1 };
CurveConversionRootSigDesc.mStaticSamplerCount = 1;
CurveConversionRootSigDesc.ppStaticSamplerNames = pColorConvertStaticSamplerNames;
CurveConversionRootSigDesc.ppStaticSamplers = &pSamplerBilinearClamp;
addRootSignature(pRenderer, &CurveConversionRootSigDesc, &pRootSigCurveConversionPass);
RootSignatureDesc sunPassShaderRootSigDesc = { &pSunPass, 1 };
addRootSignature(pRenderer, &sunPassShaderRootSigDesc, &pRootSigSunPass);
const char* pGodRayStaticSamplerNames[] = { "uSampler0" };
RootSignatureDesc godrayPassShaderRootSigDesc = { &pGodRayPass, 1 };
godrayPassShaderRootSigDesc.mStaticSamplerCount = 1;
godrayPassShaderRootSigDesc.ppStaticSamplerNames = pGodRayStaticSamplerNames;
godrayPassShaderRootSigDesc.ppStaticSamplers = &pSamplerBilinearClamp;
addRootSignature(pRenderer, &godrayPassShaderRootSigDesc, &pRootSigGodRayPass);
const char* pPresentStaticSamplerNames[] = { "uSampler0" };
RootSignatureDesc finalShaderRootSigDesc = { &pShaderPresentPass, 1 };
finalShaderRootSigDesc.mStaticSamplerCount = 1;
finalShaderRootSigDesc.ppStaticSamplerNames = pPresentStaticSamplerNames;
finalShaderRootSigDesc.ppStaticSamplers = &pSamplerBilinear;
addRootSignature(pRenderer, &finalShaderRootSigDesc, &pRootSigPresentPass);
const char* pSkyboxSamplerName = "skyboxSampler";
RootSignatureDesc skyboxRootDesc = { &pShaderSkybox, 1 };
skyboxRootDesc.mStaticSamplerCount = 1;
skyboxRootDesc.ppStaticSamplerNames = &pSkyboxSamplerName;
skyboxRootDesc.ppStaticSamplers = &pSamplerBilinear;
addRootSignature(pRenderer, &skyboxRootDesc, &pRootSingatureSkybox);
/************************************************************************/
// Setup descriptor binder
/************************************************************************/
addDescriptorSets();
/************************************************************************/
// Setup indirect command signatures
/************************************************************************/
#if defined(DIRECT3D12)
IndirectArgumentDescriptor indirectArgs[2] = {};
indirectArgs[0].mType = INDIRECT_CONSTANT;
indirectArgs[0].pName = "indirectRootConstant";
indirectArgs[1].mType = INDIRECT_DRAW_INDEX;
CommandSignatureDesc vbPassDesc = { pRootSignatureVBPass, 2, indirectArgs };
addIndirectCommandSignature(pRenderer, &vbPassDesc, &pCmdSignatureVBPass);
CommandSignatureDesc deferredPassDesc = { pRootSignatureDeferredPass, 2, indirectArgs };
addIndirectCommandSignature(pRenderer, &deferredPassDesc, &pCmdSignatureDeferredPass);
#else
// Indicate the renderer that we want to use non-indexed geometry.
IndirectArgumentDescriptor indirectArgs[1] = {};
#if defined(METAL)
indirectArgs[0].mType = INDIRECT_COMMAND_BUFFER;
#else
indirectArgs[0].mType = INDIRECT_DRAW_INDEX;
#endif
CommandSignatureDesc vbPassDesc = { pRootSignatureVBPass, 1, indirectArgs };
CommandSignatureDesc deferredPassDesc = { pRootSignatureDeferredPass, 1, indirectArgs };
addIndirectCommandSignature(pRenderer, &vbPassDesc, &pCmdSignatureVBPass);
addIndirectCommandSignature(pRenderer, &deferredPassDesc, &pCmdSignatureDeferredPass);
#endif
#if defined(METAL)
indirectArgs[0].mType = INDIRECT_COMMAND_BUFFER_OPTIMIZE;
CommandSignatureDesc icbOptimizationPassDesc = { NULL, 1, indirectArgs };
addIndirectCommandSignature(pRenderer, &icbOptimizationPassDesc, &pCmdSignatureICBOptimize);
#endif
// Create geometry for light rendering
createCubeBuffers(pRenderer, &pVertexBufferCube, &pIndexBufferCube);
//Generate sky box vertex buffer
static const float skyBoxPoints[] =
{
0.5f, -0.5f, -0.5f, 1.0f, // -z
-0.5f, -0.5f, -0.5f, 1.0f, -0.5f, 0.5f, -0.5f, 1.0f, -0.5f, 0.5f,
-0.5f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f,
-0.5f, -0.5f, 0.5f, 1.0f, //-x
-0.5f, -0.5f, -0.5f, 1.0f, -0.5f, 0.5f, -0.5f, 1.0f, -0.5f, 0.5f,
-0.5f, 1.0f, -0.5f, 0.5f, 0.5f, 1.0f, -0.5f, -0.5f, 0.5f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, //+x
0.5f, -0.5f, 0.5f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.5f, 0.5f,
0.5f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f,
-0.5f, -0.5f, 0.5f, 1.0f, // +z
-0.5f, 0.5f, 0.5f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.5f, 0.5f,
0.5f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, -0.5f, -0.5f, 0.5f, 1.0f,
-0.5f, 0.5f, -0.5f, 1.0f, //+y
0.5f, 0.5f, -0.5f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.5f, 0.5f,
0.5f, 1.0f, -0.5f, 0.5f, 0.5f, 1.0f, -0.5f, 0.5f, -0.5f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, //-y
0.5f, -0.5f, -0.5f, 1.0f, -0.5f, -0.5f, -0.5f, 1.0f, -0.5f, -0.5f,
-0.5f, 1.0f, -0.5f, -0.5f, 0.5f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f,
};
uint64_t skyBoxDataSize = 4 * 6 * 6 * sizeof(float);
BufferLoadDesc skyboxVbDesc = {};
skyboxVbDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_VERTEX_BUFFER;
skyboxVbDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
skyboxVbDesc.mDesc.mSize = skyBoxDataSize;
skyboxVbDesc.pData = skyBoxPoints;
skyboxVbDesc.mDesc.mFlags = BUFFER_CREATION_FLAG_OWN_MEMORY_BIT | BUFFER_CREATION_FLAG_PERSISTENT_MAP_BIT;
skyboxVbDesc.ppBuffer = &pSkyboxVertexBuffer;
addResource(&skyboxVbDesc, NULL);
gVertexLayoutSun.mAttribCount = 3;
gVertexLayoutSun.mAttribs[0].mSemantic = SEMANTIC_POSITION;
gVertexLayoutSun.mAttribs[0].mFormat = TinyImageFormat_R32G32B32_SFLOAT;
gVertexLayoutSun.mAttribs[0].mBinding = 0;
gVertexLayoutSun.mAttribs[0].mLocation = 0;
gVertexLayoutSun.mAttribs[0].mOffset = 0;
gVertexLayoutSun.mAttribs[1].mSemantic = SEMANTIC_NORMAL;
gVertexLayoutSun.mAttribs[1].mFormat = TinyImageFormat_R32G32B32_SFLOAT;
gVertexLayoutSun.mAttribs[1].mBinding = 0;
gVertexLayoutSun.mAttribs[1].mLocation = 1;
gVertexLayoutSun.mAttribs[1].mOffset = sizeof(float3);
gVertexLayoutSun.mAttribs[2].mSemantic = SEMANTIC_TEXCOORD0;
gVertexLayoutSun.mAttribs[2].mFormat = TinyImageFormat_R32G32_SFLOAT;
gVertexLayoutSun.mAttribs[2].mBinding = 0;
gVertexLayoutSun.mAttribs[2].mLocation = 2;
gVertexLayoutSun.mAttribs[2].mOffset = sizeof(float3) * 2;
GeometryLoadDesc loadDesc = {};
loadDesc.pFileName = gSunName;
loadDesc.ppGeometry = &pSun;
loadDesc.pVertexLayout = &gVertexLayoutSun;
addResource(&loadDesc, NULL);
/************************************************************************/
// Setup compute pipelines for triangle filtering
/************************************************************************/
PipelineDesc pipelineDesc = {};
pipelineDesc.pCache = pPipelineCache;
pipelineDesc.mType = PIPELINE_TYPE_COMPUTE;
ComputePipelineDesc& pipelineSettings = pipelineDesc.mComputeDesc;
pipelineSettings.pShaderProgram = pShaderClearBuffers;
pipelineSettings.pRootSignature = pRootSignatureTriangleFiltering;
addPipeline(pRenderer, &pipelineDesc, &pPipelineClearBuffers);
// Create the compute pipeline for GPU triangle filtering
pipelineSettings.pShaderProgram = pShaderTriangleFiltering;
pipelineSettings.pRootSignature = pRootSignatureTriangleFiltering;
addPipeline(pRenderer, &pipelineDesc, &pPipelineTriangleFiltering);
pipelineSettings.pShaderProgram = pShaderBatchCompaction;
pipelineSettings.pRootSignature = pRootSignatureTriangleFiltering;
addPipeline(pRenderer, &pipelineDesc, &pPipelineBatchCompaction);
#if defined(METAL)
pipelineSettings.pShaderProgram = pShaderICBGenerator;
pipelineSettings.pRootSignature = pRootSignatureTriangleFiltering;
addPipeline(pRenderer, &pipelineDesc, &pPipelineICBGenerator);
#endif
// Setup the clearing light clusters pipeline
pipelineSettings.pShaderProgram = pShaderClearLightClusters;
pipelineSettings.pRootSignature = pRootSignatureLightClusters;
addPipeline(pRenderer, &pipelineDesc, &pPipelineClearLightClusters);
// Setup the compute the light clusters pipeline
pipelineSettings.pShaderProgram = pShaderClusterLights;
pipelineSettings.pRootSignature = pRootSignatureLightClusters;
addPipeline(pRenderer, &pipelineDesc, &pPipelineClusterLights);
GuiDesc guiDesc = {};
guiDesc.mStartPosition = vec2(225.0f, 100.0f);
pGuiWindow = gAppUI.AddGuiComponent(GetName(), &guiDesc);
pGuiWindow->mFlags = GUI_COMPONENT_FLAGS_NO_RESIZE;
/************************************************************************/
// Most important options
/************************************************************************/
static const char* renderModeNames[] = { "Visibility Buffer", "Deferred Shading", NULL };
static const RenderMode renderModeValues[] = {
RENDERMODE_VISBUFF,
RENDERMODE_DEFERRED,
};
// Default NX settings for better performance.
#if NX64
// Async compute is not optimal on the NX platform. Turning this off to make use of default graphics queue for triangle visibility.
gAppSettings.mAsyncCompute = false;
// High fill rate features are also disabled by default for performance.
gAppSettings.mEnableGodray = false;
gAppSettings.mEnableHDAO = false;
#endif
// Reset graphics with a button.
ButtonWidget testGPUReset("ResetGraphicsDevice");
testGPUReset.pOnEdited = testGraphicsReset;
pGuiWindow->AddWidget(testGPUReset);
DropdownWidget renderMode("Render Mode", (uint32_t*)&gAppSettings.mRenderMode, renderModeNames, (uint32_t*)renderModeValues, 2U);
pGuiWindow->AddWidget(renderMode);
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 !defined(TARGET_IOS)
CheckboxWidget vsyncProp("Toggle VSync", &gAppSettings.mToggleVSync);
pGuiWindow->AddWidget(vsyncProp);
#endif
CheckboxWidget debugTargets("Draw Debug Targets", &gAppSettings.mDrawDebugTargets);
pGuiWindow->AddWidget(debugTargets);
/************************************************************************/
/************************************************************************/
// DirectX 12 Only
#if defined(DIRECT3D12)
static const char* outputModeNames[] = { "SDR", "HDR10", NULL };
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);
#endif
static const char* lightingModeNames[] = { "Phong", "Physically Based Rendering", NULL };
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, float4(0.0f), float4(30.0f), float4(0.01f));
pGuiWindow->AddWidget(lightColorUI);
CheckboxWidget toggleGR("Enable Godray", &gAppSettings.mEnableGodray);
pGuiWindow->AddWidget(toggleGR);
gAppSettings.mDynamicUIWidgetsGR.AddWidget(SliderFloatWidget("God Ray : Sun Size", &gAppSettings.mSunSize, 1.0f, 1000.0f));
gAppSettings.mDynamicUIWidgetsGR.AddWidget(SliderFloatWidget("God Ray: Exposure", &gAppSettings.gGodrayInfo.exposure, 0.0f, 0.1f, 0.001f));
gAppSettings.mDynamicUIWidgetsGR.AddWidget(SliderUintWidget("God Ray: Quality", &gAppSettings.gGodrayInteration, 1, 4));
if (gAppSettings.mEnableGodray)
gAppSettings.mDynamicUIWidgetsGR.ShowWidgets(pGuiWindow);
//SliderFloatWidget esm("Shadow Control", &gAppSettings.mEsmControl, 0, 200.0f);
//pGuiWindow->AddWidget(esm);
CheckboxWidget localLight("Enable Random Point Lights", &gAppSettings.mRenderLocalLights);
pGuiWindow->AddWidget(localLight);
/************************************************************************/
// Rendering Settings
/************************************************************************/
static const char* displayColorRangeNames[] = { "RGB", NULL };
static const DisplayColorRange displayColorRangeValues[] = { ColorRange_RGB };
static const char* displaySignalRangeNames[] = { "Range Full", "Range Limited", NULL };
static const DisplaySignalRange displaySignalRangeValues[] = { Display_SIGNAL_RANGE_FULL, Display_SIGNAL_RANGE_NARROW };
static const char* displayColorSpaceNames[] = { "ColorSpace Rec709", "ColorSpace Rec2020", "ColorSpace P3D65", NULL };
static const DisplayColorSpace displayColorSpaceValues[] = { ColorSpace_Rec709, ColorSpace_Rec2020, ColorSpace_P3D65 };
gAppSettings.mDisplaySetting.AddWidget(DropdownWidget(
"Display Color Range", (uint32_t*)&gAppSettings.mDisplayColorRange, displayColorRangeNames,
(uint32_t*)displayColorRangeValues, 1U)
);
gAppSettings.mDisplaySetting.AddWidget(DropdownWidget(
"Display Signal Range", (uint32_t*)&gAppSettings.mDisplaySignalRange, displaySignalRangeNames,
(uint32_t*)displaySignalRangeValues, 2U)
);
gAppSettings.mDisplaySetting.AddWidget(DropdownWidget(
"Display Color Space", (uint32_t*)&gAppSettings.mCurrentSwapChainColorSpace, displayColorSpaceNames,
(uint32_t*)displayColorSpaceValues, 3U)
);
/************************************************************************/
// HDAO Settings
/************************************************************************/
CheckboxWidget toggleAO("Enable HDAO", &gAppSettings.mEnableHDAO);
pGuiWindow->AddWidget(toggleAO);
gAppSettings.mDynamicUIWidgetsAO.AddWidget(SliderFloatWidget("AO accept radius", &gAppSettings.mAcceptRadius, 0, 10));
gAppSettings.mDynamicUIWidgetsAO.AddWidget(SliderFloatWidget("AO reject radius", &gAppSettings.mRejectRadius, 0, 10));
gAppSettings.mDynamicUIWidgetsAO.AddWidget(SliderFloatWidget("AO intensity radius", &gAppSettings.mAOIntensity, 0, 10));
gAppSettings.mDynamicUIWidgetsAO.AddWidget(SliderIntWidget("AO Quality", &gAppSettings.mAOQuality, 1, 4));
if (gAppSettings.mEnableHDAO)
gAppSettings.mDynamicUIWidgetsAO.ShowWidgets(pGuiWindow);
static const char* curveConversionModeNames[] = { "Linear Scale", "Scurve", NULL };
static const CurveConversionMode curveConversionValues[] = { CurveConversion_LinearScale, CurveConversion_SCurve };
DropdownWidget curveConversionMode(
"Curve Conversion", (uint32_t*)&gAppSettings.mCurveConversionMode, curveConversionModeNames, (uint32_t*)curveConversionValues,
2U);
pGuiWindow->AddWidget(curveConversionMode);
gAppSettings.mLinearScale.AddWidget(SliderFloatWidget("Linear Scale", &gAppSettings.LinearScale, 0, 300.0f));
if (gAppSettings.mCurveConversionMode == CurveConversion_LinearScale)
{
gAppSettings.mLinearScale.ShowWidgets(pGuiWindow);
}
gAppSettings.mSCurve.AddWidget(SliderFloatWidget("SCurve: Scale Factor", &gAppSettings.SCurveScaleFactor, 0, 10.0f));
gAppSettings.mSCurve.AddWidget(SliderFloatWidget("SCurve: SMin", &gAppSettings.SCurveSMin, 0, 2.0f));
gAppSettings.mSCurve.AddWidget(SliderFloatWidget("SCurve: SMid", &gAppSettings.SCurveSMid, 0, 20.0f));
gAppSettings.mSCurve.AddWidget(SliderFloatWidget("SCurve: SMax", &gAppSettings.SCurveSMax, 0, 100.0f));
gAppSettings.mSCurve.AddWidget(SliderFloatWidget("SCurve: TMin", &gAppSettings.SCurveTMin, 0, 10.0f));
gAppSettings.mSCurve.AddWidget(SliderFloatWidget("SCurve: TMid", &gAppSettings.SCurveTMid, 0, 300.0f));
gAppSettings.mSCurve.AddWidget(SliderFloatWidget("SCurve: TMax", &gAppSettings.SCurveTMax, 0, 4000.0f));
gAppSettings.mSCurve.AddWidget(SliderFloatWidget("SCurve: Slope Factor", &gAppSettings.SCurveSlopeFactor, 0, 3.0f));
if (gAppSettings.mOutputMode != OutputMode::OUTPUT_MODE_SDR && gAppSettings.mCurveConversionMode == CurveConversion_SCurve)
{
gAppSettings.mSCurve.ShowWidgets(pGuiWindow);
gSCurveInfomation.UseSCurve = 1.0f;
}
#if defined(_WINDOWS)
if (!pWindow->fullScreen)
pGuiWindow->RemoveWidget(gResolutionProperty);
#endif
/************************************************************************/
/************************************************************************/
// Finish the resource loading process since the next code depends on the loaded resources
waitThreadSystemIdle(pThreadSystem);
waitForAllResourceLoads();
gDiffuseMapsStorage = (Texture*)tf_malloc(sizeof(Texture) * gDiffuseMaps.size());
gNormalMapsStorage = (Texture*)tf_malloc(sizeof(Texture) * gNormalMaps.size());
gSpecularMapsStorage = (Texture*)tf_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(pScene);
#if defined(METAL)
for (uint32_t j = 0; j < gImageCount; ++j)
{
BufferLoadDesc indirectCommandBuffertDesc = {};
indirectCommandBuffertDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_INDIRECT_COMMAND_BUFFER | DESCRIPTOR_TYPE_BUFFER;
indirectCommandBuffertDesc.mDesc.mFlags = BUFFER_CREATION_FLAG_OWN_MEMORY_BIT; // required for ICB in Metal that allocated on device
indirectCommandBuffertDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
indirectCommandBuffertDesc.mDesc.mElementCount = MAX_DRAWS_INDIRECT * 2; // opaque + alpha
indirectCommandBuffertDesc.mDesc.mICBDrawType = INDIRECT_DRAW_INDEX;
indirectCommandBuffertDesc.mDesc.mICBMaxVertexBufferBind = UINT_VBPASS_MAX;
indirectCommandBuffertDesc.mDesc.mICBMaxFragmentBufferBind = UINT_VBPASS_MAX;
indirectCommandBuffertDesc.ppBuffer = &pIndirectCommandBufferShadow[j];
indirectCommandBuffertDesc.mDesc.pName = "Indirect Command Buffer Shadow";
addResource(&indirectCommandBuffertDesc, NULL);
indirectCommandBuffertDesc.ppBuffer = &pIndirectCommandBufferCamera[j];
indirectCommandBuffertDesc.mDesc.pName = "Indirect Command Buffer Camera";
addResource(&indirectCommandBuffertDesc, NULL);
}
// drawId buffer for ICB
uint32_t drawIds[MAX_DRAWS_INDIRECT * 2] = {};
for (uint32_t i = 0; i < MAX_DRAWS_INDIRECT * 2; ++i)
{
drawIds[i] = i;
}
BufferLoadDesc drawIDBufferDesc = {};
drawIDBufferDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_RW_BUFFER | DESCRIPTOR_TYPE_BUFFER;
drawIDBufferDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
drawIDBufferDesc.mDesc.mElementCount = MAX_DRAWS_INDIRECT * 2;
drawIDBufferDesc.mDesc.mStructStride = sizeof(uint32_t);
drawIDBufferDesc.mDesc.mSize = drawIDBufferDesc.mDesc.mElementCount * drawIDBufferDesc.mDesc.mStructStride;
drawIDBufferDesc.ppBuffer = &pDrawIDBuffer;
drawIDBufferDesc.pData = drawIds;
drawIDBufferDesc.mDesc.pName = "DrawId Buffer";
addResource(&drawIDBufferDesc, NULL);
#endif
LOGF(LogLevel::eINFO, "Setup buffers : %f ms", setupBuffersTimer.GetUSec(true) / 1000.0f);
LOGF(LogLevel::eINFO, "Total Load Time : %f ms", timer.GetUSec(true) / 1000.0f);
removeScene(pScene);
}
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(gAppSettings.mEnableGodray ? pSwapChain->ppRenderTargets : &pIntermediateRenderTarget))
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)
/************************************************************************/
DepthStateDesc depthStateDesc = {};
depthStateDesc.mDepthTest = true;
depthStateDesc.mDepthWrite = true;
depthStateDesc.mDepthFunc = CMP_LEQUAL;
DepthStateDesc depthStateDisableDesc = {};
RasterizerStateDesc rasterizerStateCullNoneDesc = { CULL_MODE_NONE };
RasterizerStateDesc rasterizerStateCullBackDesc = { CULL_MODE_BACK };
#if (MSAASAMPLECOUNT > 1)
RasterizerStateDesc rasterizerStateCullFrontMsDesc = { CULL_MODE_FRONT, 0, 0, FILL_MODE_SOLID, true };
RasterizerStateDesc rasterizerStateCullNoneMsDesc = { CULL_MODE_NONE, 0, 0, FILL_MODE_SOLID, true };
#else
RasterizerStateDesc rasterizerStateCullFrontDesc = { CULL_MODE_FRONT };
#endif
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;
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;
VertexLayout vertexLayout = {};
vertexLayout.mAttribCount = 4;
vertexLayout.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayout.mAttribs[0].mFormat = TinyImageFormat_R32G32B32_SFLOAT;
vertexLayout.mAttribs[0].mBinding = 0;
vertexLayout.mAttribs[0].mLocation = 0;
vertexLayout.mAttribs[1].mSemantic = SEMANTIC_TEXCOORD0;
vertexLayout.mAttribs[1].mFormat = TinyImageFormat_R32_UINT;
vertexLayout.mAttribs[1].mBinding = 1;
vertexLayout.mAttribs[1].mLocation = 1;
vertexLayout.mAttribs[2].mSemantic = SEMANTIC_NORMAL;
vertexLayout.mAttribs[2].mFormat = TinyImageFormat_R32_UINT;
vertexLayout.mAttribs[2].mBinding = 2;
vertexLayout.mAttribs[2].mLocation = 2;
vertexLayout.mAttribs[3].mSemantic = SEMANTIC_TANGENT;
vertexLayout.mAttribs[3].mFormat = TinyImageFormat_R32_UINT;
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 = TinyImageFormat_R32G32B32_SFLOAT;
vertexLayoutPosAndTex.mAttribs[0].mBinding = 0;
vertexLayoutPosAndTex.mAttribs[0].mLocation = 0;
vertexLayoutPosAndTex.mAttribs[1].mSemantic = SEMANTIC_TEXCOORD0;
vertexLayoutPosAndTex.mAttribs[1].mFormat = TinyImageFormat_R32_UINT;
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 = TinyImageFormat_R32G32B32_SFLOAT;
vertexLayoutPositionOnly.mAttribs[0].mBinding = 0;
vertexLayoutPositionOnly.mAttribs[0].mLocation = 0;
vertexLayoutPositionOnly.mAttribs[0].mOffset = 0;
/************************************************************************/
// Setup the Shadow Pass Pipeline
/************************************************************************/
// Setup pipeline settings
PipelineDesc pipelineDesc = {};
pipelineDesc.pCache = pPipelineCache;
pipelineDesc.mType = PIPELINE_TYPE_GRAPHICS;
GraphicsPipelineDesc& shadowPipelineSettings = pipelineDesc.mGraphicsDesc;
shadowPipelineSettings = { 0 };
shadowPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
shadowPipelineSettings.pDepthState = &depthStateDesc;
shadowPipelineSettings.mDepthStencilFormat = pRenderTargetShadow->mFormat;
shadowPipelineSettings.mSampleCount = pRenderTargetShadow->mSampleCount;
shadowPipelineSettings.mSampleQuality = pRenderTargetShadow->mSampleQuality;
shadowPipelineSettings.pRootSignature = pRootSignatureVBPass;
#if defined(METAL)
shadowPipelineSettings.mSupportIndirectCommandBuffer = true;
#endif
#if (MSAASAMPLECOUNT > 1)
shadowPipelineSettings.pRasterizerState = &rasterizerStateCullFrontMsDesc;
#else
shadowPipelineSettings.pRasterizerState = &rasterizerStateCullFrontDesc;
#endif
shadowPipelineSettings.pVertexLayout = &vertexLayoutPositionOnly;
shadowPipelineSettings.pShaderProgram = pShaderShadowPass[0];
addPipeline(pRenderer, &pipelineDesc, &pPipelineShadowPass[0]);
shadowPipelineSettings.pVertexLayout = &vertexLayoutPosAndTex;
shadowPipelineSettings.pShaderProgram = pShaderShadowPass[1];
addPipeline(pRenderer, &pipelineDesc, &pPipelineShadowPass[1]);
/************************************************************************/
// Setup the Visibility Buffer Pass Pipeline
/************************************************************************/
// Setup pipeline settings
GraphicsPipelineDesc& vbPassPipelineSettings = pipelineDesc.mGraphicsDesc;
vbPassPipelineSettings = { 0 };
vbPassPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
vbPassPipelineSettings.mRenderTargetCount = 1;
vbPassPipelineSettings.pDepthState = &depthStateDesc;
vbPassPipelineSettings.pColorFormats = &pRenderTargetVBPass->mFormat;
vbPassPipelineSettings.mSampleCount = pRenderTargetVBPass->mSampleCount;
vbPassPipelineSettings.mSampleQuality = pRenderTargetVBPass->mSampleQuality;
vbPassPipelineSettings.mDepthStencilFormat = pDepthBuffer->mFormat;
vbPassPipelineSettings.pRootSignature = pRootSignatureVBPass;
vbPassPipelineSettings.pVertexLayout = &vertexLayoutPosAndTex;
#if defined(METAL)
vbPassPipelineSettings.mSupportIndirectCommandBuffer = true;
#endif
for (uint32_t i = 0; i < gNumGeomSets; ++i)
{
if (i == GEOMSET_OPAQUE)
vbPassPipelineSettings.pVertexLayout = &vertexLayoutPositionOnly;
else
vbPassPipelineSettings.pVertexLayout = &vertexLayoutPosAndTex;
#if (MSAASAMPLECOUNT > 1)
vbPassPipelineSettings.pRasterizerState = i == GEOMSET_ALPHATESTED ? &rasterizerStateCullNoneMsDesc : &rasterizerStateCullFrontMsDesc;
#else
vbPassPipelineSettings.pRasterizerState = i == GEOMSET_ALPHATESTED ? &rasterizerStateCullNoneDesc : &rasterizerStateCullFrontDesc;
#endif
vbPassPipelineSettings.pShaderProgram = pShaderVisibilityBufferPass[i];
#if defined(XBOX)
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;
edescs[1].pixelShaderOptions.depthBeforeShader = !i ? PIXEL_SHADER_OPTION_DEPTH_BEFORE_SHADER_ENABLE : PIXEL_SHADER_OPTION_DEPTH_BEFORE_SHADER_DEFAULT;
pipelineDesc.pPipelineExtensions = edescs;
pipelineDesc.mExtensionCount = sizeof(edescs) / sizeof(edescs[0]);
#endif
addPipeline(pRenderer, &pipelineDesc, &pPipelineVisibilityBufferPass[i]);
pipelineDesc.mExtensionCount = 0;
}
/************************************************************************/
// 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 = pipelineDesc.mGraphicsDesc;
vbShadePipelineSettings = { 0 };
vbShadePipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
vbShadePipelineSettings.mRenderTargetCount = 1;
vbShadePipelineSettings.pDepthState = &depthStateDisableDesc;
#if (MSAASAMPLECOUNT > 1)
vbShadePipelineSettings.pRasterizerState = &rasterizerStateCullNoneMsDesc;
#else
vbShadePipelineSettings.pRasterizerState = &rasterizerStateCullNoneDesc;
#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->mFormat;
vbShadePipelineSettings.mSampleQuality = pRenderTargetMSAA->mSampleQuality;
#else
//vbShadePipelineSettings.pColorFormats = &pSwapChain->ppRenderTargets[0]->mFormat;
vbShadePipelineSettings.pColorFormats = &pIntermediateRenderTarget->mFormat;
vbShadePipelineSettings.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
#endif
#if defined(XBOX)
ExtendedGraphicsPipelineDesc edescs[2] = {};
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;
edescs[1].pixelShaderOptions.depthBeforeShader = !i ? PIXEL_SHADER_OPTION_DEPTH_BEFORE_SHADER_ENABLE : PIXEL_SHADER_OPTION_DEPTH_BEFORE_SHADER_DEFAULT;
pipelineDesc.pPipelineExtensions = edescs;
pipelineDesc.mExtensionCount = sizeof(edescs) / sizeof(edescs[0]);
#endif
addPipeline(pRenderer, &pipelineDesc, &pPipelineVisibilityBufferShadeSrgb[i]);
pipelineDesc.mExtensionCount = 0;
}
/************************************************************************/
// Setup the resources needed for the Deferred Pass Pipeline
/************************************************************************/
TinyImageFormat deferredFormats[DEFERRED_RT_COUNT] = {};
for (uint32_t i = 0; i < DEFERRED_RT_COUNT; ++i)
{
deferredFormats[i] = pRenderTargetDeferredPass[i]->mFormat;
}
GraphicsPipelineDesc& deferredPassPipelineSettings = pipelineDesc.mGraphicsDesc;
deferredPassPipelineSettings = { 0 };
deferredPassPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
deferredPassPipelineSettings.mRenderTargetCount = DEFERRED_RT_COUNT;
deferredPassPipelineSettings.pDepthState = &depthStateDesc;
deferredPassPipelineSettings.pColorFormats = deferredFormats;
deferredPassPipelineSettings.mSampleCount = pDepthBuffer->mSampleCount;
deferredPassPipelineSettings.mSampleQuality = pDepthBuffer->mSampleQuality;
deferredPassPipelineSettings.mDepthStencilFormat = pDepthBuffer->mFormat;
deferredPassPipelineSettings.pRootSignature = pRootSignatureDeferredPass;
deferredPassPipelineSettings.pVertexLayout = &vertexLayout;
#if defined(METAL)
deferredPassPipelineSettings.mSupportIndirectCommandBuffer = true;
#endif
// Create pipelines for geometry sets
for (uint32_t i = 0; i < gNumGeomSets; ++i)
{
#if (MSAASAMPLECOUNT > 1)
deferredPassPipelineSettings.pRasterizerState =
i == GEOMSET_ALPHATESTED ? &rasterizerStateCullNoneMsDesc : &rasterizerStateCullFrontMsDesc;
#else
deferredPassPipelineSettings.pRasterizerState = i == GEOMSET_ALPHATESTED ? &rasterizerStateCullNoneDesc : &rasterizerStateCullFrontDesc;
#endif
deferredPassPipelineSettings.pShaderProgram = pShaderDeferredPass[i];
addPipeline(pRenderer, &pipelineDesc, &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 = pipelineDesc.mGraphicsDesc;
deferredShadePipelineSettings = { 0 };
deferredShadePipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
deferredShadePipelineSettings.mRenderTargetCount = 1;
deferredShadePipelineSettings.pDepthState = &depthStateDisableDesc;
#if (MSAASAMPLECOUNT > 1)
deferredShadePipelineSettings.pRasterizerState = &rasterizerStateCullNoneMsDesc;
#else
deferredShadePipelineSettings.pRasterizerState = &rasterizerStateCullNoneDesc;
#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->mFormat;
deferredShadePipelineSettings.mSampleQuality = pRenderTargetMSAA->mSampleQuality;
#else
//deferredShadePipelineSettings.pColorFormats = &pSwapChain->ppRenderTargets[0]->mFormat;
deferredShadePipelineSettings.pColorFormats = &pIntermediateRenderTarget->mFormat;
deferredShadePipelineSettings.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
#endif
addPipeline(pRenderer, &pipelineDesc, &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 = TinyImageFormat_R32G32B32A32_SFLOAT;
vertexLayoutPointLightShade.mAttribs[0].mBinding = 0;
vertexLayoutPointLightShade.mAttribs[0].mLocation = 0;
vertexLayoutPointLightShade.mAttribs[0].mOffset = 0;
// Setup pipeline settings
GraphicsPipelineDesc& deferredPointLightPipelineSettings = pipelineDesc.mGraphicsDesc;
//deferredPointLightPipelineSettings = {0};
deferredPointLightPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
deferredPointLightPipelineSettings.mRenderTargetCount = 1;
deferredPointLightPipelineSettings.pBlendState = &blendStateDesc;
deferredPointLightPipelineSettings.pDepthState = &depthStateDisableDesc;
deferredPointLightPipelineSettings.pColorFormats = deferredShadePipelineSettings.pColorFormats;
deferredPointLightPipelineSettings.mSampleCount = deferredShadePipelineSettings.mSampleCount;
deferredPointLightPipelineSettings.pRasterizerState = &rasterizerStateCullBackDesc;
deferredPointLightPipelineSettings.pRootSignature = pRootSignatureDeferredShadePointLight;
deferredPointLightPipelineSettings.pShaderProgram = pShaderDeferredShadePointLight;
deferredPointLightPipelineSettings.pVertexLayout = &vertexLayoutPointLightShade;
addPipeline(pRenderer, &pipelineDesc, &pPipelineDeferredShadePointLightSrgb);
/************************************************************************/
// Setup HDAO post process pipeline
/************************************************************************/
GraphicsPipelineDesc& aoPipelineSettings = pipelineDesc.mGraphicsDesc;
aoPipelineSettings = { 0 };
aoPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
aoPipelineSettings.mRenderTargetCount = 1;
aoPipelineSettings.pDepthState = &depthStateDisableDesc;
aoPipelineSettings.pColorFormats = &pRenderTargetAO->mFormat;
aoPipelineSettings.mSampleCount = pRenderTargetAO->mSampleCount;
aoPipelineSettings.mSampleQuality = pRenderTargetAO->mSampleQuality;
aoPipelineSettings.pRasterizerState = &rasterizerStateCullNoneDesc;
aoPipelineSettings.pRootSignature = pRootSignatureAO;
for (uint32_t i = 0; i < 4; ++i)
{
aoPipelineSettings.pShaderProgram = pShaderAO[i];
addPipeline(pRenderer, &pipelineDesc, &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 = TinyImageFormat_R32G32B32A32_SFLOAT;
vertexLayoutSkybox.mAttribs[0].mBinding = 0;
vertexLayoutSkybox.mAttribs[0].mLocation = 0;
vertexLayoutSkybox.mAttribs[0].mOffset = 0;
GraphicsPipelineDesc& pipelineSettings = pipelineDesc.mGraphicsDesc;
pipelineSettings = { 0 };
pipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettings.mRenderTargetCount = 1;
pipelineSettings.pDepthState = NULL;
pipelineSettings.pBlendState = &blendStateSkyBoxDesc;
pipelineSettings.pColorFormats = &pIntermediateRenderTarget->mFormat;
pipelineSettings.mSampleCount = pSwapChain->ppRenderTargets[0]->mSampleCount;
pipelineSettings.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
//pipelineSettings.mDepthStencilFormat = pDepthBuffer->mFormat;
pipelineSettings.pRootSignature = pRootSingatureSkybox;
pipelineSettings.pShaderProgram = pShaderSkybox;
pipelineSettings.pVertexLayout = &vertexLayoutSkybox;
pipelineSettings.pRasterizerState = &rasterizerStateCullNoneDesc;
addPipeline(pRenderer, &pipelineDesc, &pSkyboxPipeline);
/************************************************************************/
// Setup Sun pipeline
/************************************************************************/
//layout and pipeline for skybox draw
//Draw Sun
GraphicsPipelineDesc& pipelineSettingsSun = pipelineDesc.mGraphicsDesc;
pipelineSettingsSun = { 0 };
pipelineSettingsSun.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettingsSun.pRasterizerState = &rasterizerStateCullBackDesc;
pipelineSettingsSun.pDepthState = &depthStateDesc;
pipelineSettingsSun.mDepthStencilFormat = pDepthBuffer->mFormat;
pipelineSettingsSun.mRenderTargetCount = 1;
pipelineSettingsSun.pColorFormats = &pRenderTargetSun->mFormat;
pipelineSettingsSun.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
pipelineSettingsSun.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
pipelineSettingsSun.pVertexLayout = &gVertexLayoutSun;
pipelineSettingsSun.pRootSignature = pRootSigSunPass;
pipelineSettingsSun.pShaderProgram = pSunPass;
addPipeline(pRenderer, &pipelineDesc, &pPipelineSunPass);
/************************************************************************/
// Setup Godray pipeline
/************************************************************************/
GraphicsPipelineDesc& pipelineSettingsGodRay = pipelineDesc.mGraphicsDesc;
pipelineSettingsGodRay = { 0 };
pipelineSettingsGodRay.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettingsGodRay.pRasterizerState = &rasterizerStateCullNoneDesc;
pipelineSettingsGodRay.mRenderTargetCount = 1;
pipelineSettingsGodRay.pColorFormats = &pRenderTargetGodRay[0]->mFormat;
pipelineSettingsGodRay.mSampleCount = pSwapChain->ppRenderTargets[0]->mSampleCount;
pipelineSettingsGodRay.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
pipelineSettingsGodRay.pRootSignature = pRootSigGodRayPass;
pipelineSettingsGodRay.pShaderProgram = pGodRayPass;
addPipeline(pRenderer, &pipelineDesc, &pPipelineGodRayPass);
/************************************************************************/
// Setup Curve Conversion pipeline
/************************************************************************/
GraphicsPipelineDesc& pipelineSettingsCurveConversion = pipelineDesc.mGraphicsDesc;
pipelineSettingsCurveConversion = { 0 };
pipelineSettingsCurveConversion.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettingsCurveConversion.pRasterizerState = &rasterizerStateCullNoneDesc;
pipelineSettingsCurveConversion.mRenderTargetCount = 1;
pipelineSettingsCurveConversion.pColorFormats = &pCurveConversionRenderTarget->mFormat;
pipelineSettingsCurveConversion.mSampleCount = pSwapChain->ppRenderTargets[0]->mSampleCount;
pipelineSettingsCurveConversion.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
pipelineSettingsCurveConversion.pRootSignature = pRootSigCurveConversionPass;
pipelineSettingsCurveConversion.pShaderProgram = pShaderCurveConversion;
addPipeline(pRenderer, &pipelineDesc, &pPipelineCurveConversionPass);
/************************************************************************/
// Setup Present pipeline
/************************************************************************/
GraphicsPipelineDesc& pipelineSettingsFinalPass = pipelineDesc.mGraphicsDesc;
pipelineSettingsFinalPass = { 0 };
pipelineSettingsFinalPass.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettingsFinalPass.pRasterizerState = &rasterizerStateCullNoneDesc;
pipelineSettingsFinalPass.mRenderTargetCount = 1;
pipelineSettingsFinalPass.pColorFormats = &pSwapChain->ppRenderTargets[0]->mFormat;
pipelineSettingsFinalPass.mSampleCount = pSwapChain->ppRenderTargets[0]->mSampleCount;
pipelineSettingsFinalPass.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
pipelineSettingsFinalPass.pRootSignature = pRootSigPresentPass;
pipelineSettingsFinalPass.pShaderProgram = pShaderPresentPass;
addPipeline(pRenderer, &pipelineDesc, &pPipelinePresentPass);
SetupDebugTexturesWindow();
prepareDescriptorSets();
return true;
}
void Unload()
{
waitQueueIdle(pGraphicsQueue);
waitQueueIdle(pComputeQueue);
// 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();
if (pDebugTexturesWindow)
{
gAppUI.RemoveGuiComponent(pDebugTexturesWindow);
pDebugTexturesWindow = NULL;
}
if (mSettings.mQuit || mSettings.mResetGraphics)
{
removeResource(pSkybox);
removeTriangleFilteringBuffers();
gAppSettings.mDynamicUIWidgetsGR.Destroy();
gAppSettings.mDynamicUIWidgetsAO.Destroy();
gAppSettings.mLinearScale.Destroy();
gAppSettings.mSCurve.Destroy();
gAppSettings.mDisplaySetting.Destroy();
exitProfilerUI();
exitProfiler();
gAppUI.Exit();
// Destroy geometry for light rendering
removeResource(pVertexBufferCube);
removeResource(pIndexBufferCube);
// Destroy triangle filtering pipelines
removePipeline(pRenderer, pPipelineClusterLights);
removePipeline(pRenderer, pPipelineClearLightClusters);
removePipeline(pRenderer, pPipelineTriangleFiltering);
removePipeline(pRenderer, pPipelineBatchCompaction);
removePipeline(pRenderer, pPipelineClearBuffers);
#if defined(METAL)
removePipeline(pRenderer, pPipelineICBGenerator);
#endif
// Remove descriptor binder
removeDescriptorSets();
// Remove root signatures
removeRootSignature(pRenderer, pRootSignatureResolve);
removeRootSignature(pRenderer, pRootSignatureAO);
removeRootSignature(pRenderer, pRootSingatureSkybox);
removeRootSignature(pRenderer, pRootSigSunPass);
removeRootSignature(pRenderer, pRootSigGodRayPass);
removeRootSignature(pRenderer, pRootSigCurveConversionPass);
removeRootSignature(pRenderer, pRootSigPresentPass);
removeRootSignature(pRenderer, pRootSignatureLightClusters);
removeRootSignature(pRenderer, pRootSignatureTriangleFiltering);
removeRootSignature(pRenderer, pRootSignatureDeferredShadePointLight);
removeRootSignature(pRenderer, pRootSignatureDeferredShade);
removeRootSignature(pRenderer, pRootSignatureDeferredPass);
removeRootSignature(pRenderer, pRootSignatureVBShade);
removeRootSignature(pRenderer, pRootSignatureVBPass);
// Remove indirect command signatures
removeIndirectCommandSignature(pRenderer, pCmdSignatureDeferredPass);
removeIndirectCommandSignature(pRenderer, pCmdSignatureVBPass);
#if defined(METAL)
removeIndirectCommandSignature(pRenderer, pCmdSignatureICBOptimize);
#endif
/************************************************************************/
// Remove loaded scene
/************************************************************************/
// Destroy scene buffers
removeResource(pGeom);
removeResource(pSun);
removeResource(pSkyboxVertexBuffer);
/************************************************************************/
// Remove ICB resources
/************************************************************************/
#if defined(METAL)
for (uint32_t j = 0; j < gImageCount; ++j)
{
removeResource(pIndirectCommandBufferShadow[j]);
removeResource(pIndirectCommandBufferCamera[j]);
}
removeResource(pDrawIDBuffer);
#endif
// Destroy clusters
for (uint32_t i = 0; i < gMeshCount; ++i)
{
destroyClusters(&pMeshes[i]);
}
// Remove Textures
for (uint32_t i = 0; i < gMaterialCount; ++i)
{
removeResource(gDiffuseMaps[i]);
removeResource(gNormalMaps[i]);
removeResource(gSpecularMaps[i]);
}
tf_free(gDiffuseMapsStorage);
tf_free(gNormalMapsStorage);
tf_free(gSpecularMapsStorage);
tf_free(pMeshes);
gDiffuseMaps.set_capacity(0);
gNormalMaps.set_capacity(0);
gSpecularMaps.set_capacity(0);
gDiffuseMapsPacked.set_capacity(0);
gNormalMapsPacked.set_capacity(0);
gSpecularMapsPacked.set_capacity(0);
gPositionsDirections.set_capacity(0);
#if defined(_WINDOWS)
gResolutions.set_capacity(0);
gGuiResolution.resNameContainer.set_capacity(0);
gGuiResolution.resNamePointers.set_capacity(0);
gGuiResolution.resValues.set_capacity(0);
#endif
/************************************************************************/
/************************************************************************/
removeShaders();
removeSemaphore(pRenderer, pImageAcquiredSemaphore);
removeFence(pRenderer, pTransitionFences);
for (uint32_t i = 0; i < gImageCount; ++i)
{
removeCmd(pRenderer, ppCmds[i]);
removeCmdPool(pRenderer, pCmdPool[i]);
removeCmd(pRenderer, ppComputeCmds[i]);
removeCmdPool(pRenderer, pComputeCmdPool[i]);
}
removeQueue(pRenderer, pGraphicsQueue);
removeQueue(pRenderer, pComputeQueue);
removeSampler(pRenderer, pSamplerTrilinearAniso);
removeSampler(pRenderer, pSamplerBilinear);
removeSampler(pRenderer, pSamplerPointClamp);
removeSampler(pRenderer, pSamplerBilinearClamp);
PipelineCacheSaveDesc saveDesc = {};
saveDesc.pFileName = pPipelineCacheName;
savePipelineCache(pRenderer, pPipelineCache, &saveDesc);
removePipelineCache(pRenderer, pPipelineCache);
exitResourceLoaderInterface(pRenderer);
/*
#ifdef _DEBUG
ID3D12DebugDevice *pDebugDevice = NULL;
pRenderer->pDxDevice->QueryInterface(&pDebugDevice);
pDebugDevice->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL | D3D12_RLDO_IGNORE_INTERNAL);
pDebugDevice->Release();
#endif
*/
removeRenderer(pRenderer);
}
}
void Update(float deltaTime)
{
updateInputSystem(mSettings.mWidth, mSettings.mHeight);
#if !defined(TARGET_IOS)
if (pSwapChain->mEnableVsync != gAppSettings.mToggleVSync)
{
waitQueueIdle(pGraphicsQueue);
::toggleVSync(pRenderer, &pSwapChain);
}
#if defined(_WINDOWS)
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(XBOX)
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(pRenderer, gImageCount, pRenderCompleteFences);
#if defined(XBOX)
//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(XBOX)
}
#endif
}
#if !defined(TARGET_IOS)
pCameraController->update(deltaTime);
#endif
//Camera Walking Update
if (gAppSettings.cameraWalking)
{
if (gTotalElpasedTime - (0.033333f * gAppSettings.cameraWalkingSpeed) <= gCameraWalkingTime)
{
gCameraWalkingTime = 0.0f;
}
gCameraWalkingTime += deltaTime * gAppSettings.cameraWalkingSpeed;
uint currentCameraFrame = (uint)(gCameraWalkingTime / 0.00833f);
float remind = gCameraWalkingTime - (float)currentCameraFrame * 0.00833f;
float3 newPos =
v3ToF3(lerp(f3Tov3(gCameraPathData[2 * currentCameraFrame]), f3Tov3(gCameraPathData[2 * (currentCameraFrame + 1)]), remind));
pCameraController->moveTo(f3Tov3(newPos));
float3 newLookat = v3ToF3(
lerp(f3Tov3(gCameraPathData[2 * currentCameraFrame + 1]), f3Tov3(gCameraPathData[2 * (currentCameraFrame + 1) + 1]), remind));
pCameraController->lookAt(f3Tov3(newLookat));
}
gAppUI.Update(deltaTime);
updateDynamicUIElements();
updateUniformData(gFrameCount % gImageCount);
}
void Draw()
{
uint32_t presentIndex = 0;
uint32_t frameIdx = gFrameCount % gImageCount;
if (!gAppSettings.mAsyncCompute)
{
// check to see if we can use the cmd buffer
Fence* pRenderFence = pRenderCompleteFences[frameIdx];
FenceStatus fenceStatus;
getFenceStatus(pRenderer, pRenderFence, &fenceStatus);
if (fenceStatus == FENCE_STATUS_INCOMPLETE)
waitForFences(pRenderer, 1, &pRenderFence);
}
else
{
// check to see if we can use the cmd buffer
Fence* pComputeFence = pComputeCompleteFences[frameIdx];
FenceStatus fenceStatus;
getFenceStatus(pRenderer, pComputeFence, &fenceStatus);
if (fenceStatus == FENCE_STATUS_INCOMPLETE)
waitForFences(pRenderer, 1, &pComputeFence);
// check to see if we can use the cmd buffer
Fence* pRenderFence = pRenderCompleteFences[frameIdx];
//FenceStatus fenceStatus;
getFenceStatus(pRenderer, pRenderFence, &fenceStatus);
if (fenceStatus == FENCE_STATUS_INCOMPLETE)
waitForFences(pRenderer, 1, &pRenderFence);
}
/************************************************************************/
// Update uniform buffer to gpu
/************************************************************************/
BufferUpdateDesc update = { pPerFrameUniformBuffers[frameIdx] };
beginUpdateResource(&update);
*(PerFrameConstants*)update.pMappedData = gPerFrame[frameIdx].gPerFrameUniformData;
endUpdateResource(&update, NULL);
// Update uniform buffers
update = { pUniformBufferSky[frameIdx] };
beginUpdateResource(&update);
*(UniformDataSkybox*)update.pMappedData = gPerFrame[frameIdx].gUniformDataSky;
endUpdateResource(&update, NULL);
// Update uniform buffers
update = { pUniformBufferSun[frameIdx] };
update.mSize = sizeof(gPerFrame[frameIdx].gUniformDataSunMatrices);
beginUpdateResource(&update);
*(UniformDataSunMatrices*)update.pMappedData = gPerFrame[frameIdx].gUniformDataSunMatrices;
endUpdateResource(&update, NULL);
/************************************************************************/
// Async compute pass
/************************************************************************/
if (gAppSettings.mAsyncCompute && gAppSettings.mFilterTriangles && !gAppSettings.mHoldFilteredResults)
{
/************************************************************************/
// Triangle filtering async compute pass
/************************************************************************/
Cmd* computeCmd = ppComputeCmds[frameIdx];
resetCmdPool(pRenderer, pComputeCmdPool[frameIdx]);
beginCmd(computeCmd);
cmdBeginGpuFrameProfile(computeCmd, gComputeProfileToken);
triangleFilteringPass(computeCmd, gComputeProfileToken, frameIdx);
cmdBeginGpuTimestampQuery(computeCmd, gComputeProfileToken, "Clear Light Clusters");
clearLightClusters(computeCmd, frameIdx);
cmdEndGpuTimestampQuery(computeCmd, gComputeProfileToken);
if (gAppSettings.mRenderLocalLights)
{
/************************************************************************/
// Synchronization
/************************************************************************/
// Update Light clusters on the GPU
cmdBeginGpuTimestampQuery(computeCmd, gComputeProfileToken, "Compute Light Clusters");
BufferBarrier barriers[] = { { pLightClustersCount[frameIdx], RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_UNORDERED_ACCESS } };
cmdResourceBarrier(computeCmd, 1, barriers, 0, NULL, 0, NULL);
computeLightClusters(computeCmd, frameIdx);
cmdEndGpuTimestampQuery(computeCmd, gComputeProfileToken);
}
#if defined(METAL)
icbGeneration(computeCmd, gComputeProfileToken, frameIdx);
#endif
cmdEndGpuFrameProfile(computeCmd, gComputeProfileToken);
endCmd(computeCmd);
QueueSubmitDesc submitDesc = {};
submitDesc.mCmdCount = 1;
submitDesc.mSignalSemaphoreCount = 1;
submitDesc.ppCmds = &computeCmd;
submitDesc.ppSignalSemaphores = &pComputeCompleteSemaphores[frameIdx];
submitDesc.pSignalFence = pComputeCompleteFences[frameIdx];
submitDesc.mSubmitDone = (gFrameCount < 1);
queueSubmit(pComputeQueue, &submitDesc);
/************************************************************************/
/************************************************************************/
}
/************************************************************************/
// Draw Pass - Skip first frame since draw will always be one frame behind compute
/************************************************************************/
if (!gAppSettings.mAsyncCompute || gFrameCount > 0)
{
Cmd* graphicsCmd = NULL;
if (gAppSettings.mAsyncCompute)
frameIdx = ((gFrameCount - 1) % gImageCount);
pScreenRenderTarget = pIntermediateRenderTarget;
//pScreenRenderTarget = pSwapChain->ppRenderTargets[gPresentFrameIdx];
// Get command list to store rendering commands for this frame
graphicsCmd = ppCmds[frameIdx];
// Submit all render commands for this frame
resetCmdPool(pRenderer, pCmdPool[frameIdx]);
beginCmd(graphicsCmd);
cmdBeginGpuFrameProfile(graphicsCmd, gGraphicsProfileToken);
if (!gAppSettings.mAsyncCompute && gAppSettings.mFilterTriangles && !gAppSettings.mHoldFilteredResults)
{
triangleFilteringPass(graphicsCmd, gGraphicsProfileToken, frameIdx);
}
if (!gAppSettings.mAsyncCompute || !gAppSettings.mFilterTriangles)
{
cmdBeginGpuTimestampQuery(graphicsCmd, gGraphicsProfileToken, "Clear Light Clusters");
clearLightClusters(graphicsCmd, frameIdx);
cmdEndGpuTimestampQuery(graphicsCmd, gGraphicsProfileToken);
}
if ((!gAppSettings.mAsyncCompute || !gAppSettings.mFilterTriangles) && gAppSettings.mRenderLocalLights)
{
// Update Light clusters on the GPU
cmdBeginGpuTimestampQuery(graphicsCmd, gGraphicsProfileToken, "Compute Light Clusters");
BufferBarrier barriers[] = { { pLightClustersCount[frameIdx], RESOURCE_STATE_SHADER_RESOURCE, RESOURCE_STATE_UNORDERED_ACCESS } };
cmdResourceBarrier(graphicsCmd, 1, barriers, 0, NULL, 0, NULL);
computeLightClusters(graphicsCmd, frameIdx);
barriers[0] = { pLightClusters[frameIdx], RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_UNORDERED_ACCESS };
cmdResourceBarrier(graphicsCmd, 1, barriers, 0, NULL, 0, NULL);
cmdEndGpuTimestampQuery(graphicsCmd, gGraphicsProfileToken);
}
#ifdef METAL
if ((!gAppSettings.mAsyncCompute || !gAppSettings.mFilterTriangles)/* && !gAppSettings.mHoldFilteredResults*/)
{
// Indirect Command Buffer Generation
icbGeneration(graphicsCmd, gGraphicsProfileToken, frameIdx);
}
#endif
// Transition swapchain buffer to be used as a render target
RenderTargetBarrier barriers[] = {
{ pScreenRenderTarget, RESOURCE_STATE_PIXEL_SHADER_RESOURCE, RESOURCE_STATE_RENDER_TARGET },
{ pRenderTargetMSAA, RESOURCE_STATE_PIXEL_SHADER_RESOURCE, RESOURCE_STATE_RENDER_TARGET },
{ pDepthBuffer, RESOURCE_STATE_PIXEL_SHADER_RESOURCE, RESOURCE_STATE_DEPTH_WRITE },
};
cmdResourceBarrier(graphicsCmd, 0, NULL, 0, NULL, 3, barriers);
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[frameIdx][GEOMSET_ALPHATESTED][i],
RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_INDIRECT_ARGUMENT | RESOURCE_STATE_PIXEL_SHADER_RESOURCE };
barriers2[index++] = { pFilteredIndirectDrawArgumentsBuffer[frameIdx][GEOMSET_OPAQUE][i],
RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_INDIRECT_ARGUMENT | RESOURCE_STATE_PIXEL_SHADER_RESOURCE };
barriers2[index++] = { pFilteredIndexBuffer[frameIdx][i],
RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_INDEX_BUFFER | RESOURCE_STATE_PIXEL_SHADER_RESOURCE };
}
barriers2[index++] = { pFilterIndirectMaterialBuffer[frameIdx], RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_SHADER_RESOURCE };
barriers2[index++] = { pLightClusters[frameIdx], RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_PIXEL_SHADER_RESOURCE };
barriers2[index++] = { pLightClustersCount[frameIdx], RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_PIXEL_SHADER_RESOURCE };
cmdResourceBarrier(graphicsCmd, numBarriers, barriers2, 0, NULL, 0, NULL);
}
drawScene(graphicsCmd, frameIdx);
drawSkybox(graphicsCmd, frameIdx);
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[frameIdx][GEOMSET_ALPHATESTED][i],
RESOURCE_STATE_INDIRECT_ARGUMENT | RESOURCE_STATE_PIXEL_SHADER_RESOURCE, RESOURCE_STATE_UNORDERED_ACCESS };
barriers2[index++] = { pFilteredIndirectDrawArgumentsBuffer[frameIdx][GEOMSET_OPAQUE][i],
RESOURCE_STATE_INDIRECT_ARGUMENT | RESOURCE_STATE_PIXEL_SHADER_RESOURCE, RESOURCE_STATE_UNORDERED_ACCESS };
barriers2[index++] = { pFilteredIndexBuffer[frameIdx][i],
RESOURCE_STATE_INDEX_BUFFER | RESOURCE_STATE_PIXEL_SHADER_RESOURCE, RESOURCE_STATE_UNORDERED_ACCESS };
}
barriers2[index++] = { pFilterIndirectMaterialBuffer[frameIdx],
RESOURCE_STATE_SHADER_RESOURCE, RESOURCE_STATE_UNORDERED_ACCESS };
barriers2[index++] = { pLightClusters[frameIdx],
RESOURCE_STATE_PIXEL_SHADER_RESOURCE, RESOURCE_STATE_UNORDERED_ACCESS };
barriers2[index++] = { pLightClustersCount[frameIdx],
RESOURCE_STATE_PIXEL_SHADER_RESOURCE, RESOURCE_STATE_UNORDERED_ACCESS };
cmdResourceBarrier(graphicsCmd, numBarriers, barriers2, 0, NULL, 0, NULL);
}
if (gAppSettings.mEnableGodray)
{
drawGodray(graphicsCmd, frameIdx);
drawColorconversion(graphicsCmd);
}
cmdBeginGpuTimestampQuery(graphicsCmd, gGraphicsProfileToken, "UI Pass");
drawGUI(graphicsCmd, frameIdx);
cmdEndGpuTimestampQuery(graphicsCmd, gGraphicsProfileToken);
// Get the current render target for this frame
acquireNextImage(pRenderer, pSwapChain, pImageAcquiredSemaphore, NULL, &presentIndex);
presentImage(graphicsCmd, pScreenRenderTarget, pSwapChain->ppRenderTargets[presentIndex]);
cmdEndGpuFrameProfile(graphicsCmd, gGraphicsProfileToken);
endCmd(graphicsCmd);
// Submit all the work to the GPU and present
Semaphore* pWaitSemaphores[] = { pImageAcquiredSemaphore, pComputeCompleteSemaphores[frameIdx] };
QueueSubmitDesc submitDesc = {};
submitDesc.mCmdCount = 1;
submitDesc.mSignalSemaphoreCount = 1;
submitDesc.ppCmds = &graphicsCmd;
submitDesc.ppSignalSemaphores = &pRenderCompleteSemaphores[frameIdx];
submitDesc.pSignalFence = pRenderCompleteFences[frameIdx];
if (gAppSettings.mAsyncCompute)
{
submitDesc.mWaitSemaphoreCount = 2;
submitDesc.ppWaitSemaphores = pWaitSemaphores;
}
else
{
submitDesc.mWaitSemaphoreCount = 1;
submitDesc.ppWaitSemaphores = &pImageAcquiredSemaphore;
}
queueSubmit(pGraphicsQueue, &submitDesc);
QueuePresentDesc presentDesc = {};
presentDesc.mIndex = presentIndex;
presentDesc.mWaitSemaphoreCount = 1;
presentDesc.ppWaitSemaphores = &pRenderCompleteSemaphores[frameIdx];
presentDesc.pSwapChain = pSwapChain;
presentDesc.mSubmitDone = true;
PresentStatus presentStatus = queuePresent(pGraphicsQueue, &presentDesc);
flipProfiler();
if (presentStatus == PRESENT_STATUS_DEVICE_RESET)
{
Thread::Sleep(5000);// Wait for a few seconds to allow the driver to come back online before doing a reset.
mSettings.mResetGraphics = true;
}
// Test re-creating graphics resources mid app.
if (gTestGraphicsReset)
{
mSettings.mResetGraphics = true;
gTestGraphicsReset = false;
}
}
++gFrameCount;
}
const char* GetName() { return "Visibility_Buffer"; }
bool addDescriptorSets()
{
// Triangle Filtering
DescriptorSetDesc setDesc = { pRootSignatureTriangleFiltering, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetTriangleFiltering[0]);
setDesc = { pRootSignatureTriangleFiltering, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gImageCount * gNumStages }; // additional buffer for ICB on Metal
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetTriangleFiltering[1]);
// Light Clustering
setDesc = { pRootSignatureLightClusters, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetLightClusters[0]);
setDesc = { pRootSignatureLightClusters, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gImageCount };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetLightClusters[1]);
#if !defined(METAL)
// VB, Shadow
setDesc = { pRootSignatureVBPass, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetVBPass[0]);
setDesc = { pRootSignatureVBPass, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gImageCount * 2 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetVBPass[1]);
#endif
// VB Shade
setDesc = { pRootSignatureVBShade, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetVBShade[0]);
setDesc = { pRootSignatureVBShade, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gImageCount * 2 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetVBShade[1]);
// Deferred Pass
setDesc = { pRootSignatureDeferredPass, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetDeferredPass[0]);
setDesc = { pRootSignatureDeferredPass, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gImageCount * 2 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetDeferredPass[1]);
// Deferred Shade
setDesc = { pRootSignatureDeferredShade, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetDeferredShade[0]);
setDesc = { pRootSignatureDeferredShade, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gImageCount };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetDeferredShade[1]);
// Deferred Shade Lighting
setDesc = { pRootSignatureDeferredShadePointLight, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetDeferredShadePointLight[0]);
setDesc = { pRootSignatureDeferredShadePointLight, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gImageCount };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetDeferredShadePointLight[1]);
// HDAO
setDesc = { pRootSignatureAO, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetAO);
// Resolve
setDesc = { pRootSignatureResolve, DESCRIPTOR_UPDATE_FREQ_NONE, 2 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetResolve);
// Sun
setDesc = { pRootSigSunPass, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gImageCount };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetSunPass);
// God Ray
#if defined(METAL)
setDesc = { pRootSigGodRayPass, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetGodRayPassSampler);
#endif
setDesc = { pRootSigGodRayPass, DESCRIPTOR_UPDATE_FREQ_PER_DRAW, 3 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetGodRayPass);
// Curve Conversion
setDesc = { pRootSigCurveConversionPass, DESCRIPTOR_UPDATE_FREQ_NONE, 2 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetCurveConversionPass);
// Sky
setDesc = { pRootSingatureSkybox, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetSkybox[0]);
setDesc = { pRootSingatureSkybox, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gImageCount };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetSkybox[1]);
// Present
setDesc = { pRootSigPresentPass, DESCRIPTOR_UPDATE_FREQ_NONE, 2 };
addDescriptorSet(pRenderer, &setDesc, &pDescriptorSetPresentPass);
return true;
}
void removeDescriptorSets()
{
removeDescriptorSet(pRenderer, pDescriptorSetPresentPass);
removeDescriptorSet(pRenderer, pDescriptorSetSkybox[0]);
removeDescriptorSet(pRenderer, pDescriptorSetSkybox[1]);
removeDescriptorSet(pRenderer, pDescriptorSetResolve);
removeDescriptorSet(pRenderer, pDescriptorSetCurveConversionPass);
removeDescriptorSet(pRenderer, pDescriptorSetGodRayPass);
removeDescriptorSet(pRenderer, pDescriptorSetSunPass);
removeDescriptorSet(pRenderer, pDescriptorSetAO);
removeDescriptorSet(pRenderer, pDescriptorSetDeferredShadePointLight[0]);
removeDescriptorSet(pRenderer, pDescriptorSetDeferredShadePointLight[1]);
removeDescriptorSet(pRenderer, pDescriptorSetDeferredShade[0]);
removeDescriptorSet(pRenderer, pDescriptorSetDeferredShade[1]);
removeDescriptorSet(pRenderer, pDescriptorSetDeferredPass[0]);
removeDescriptorSet(pRenderer, pDescriptorSetDeferredPass[1]);
removeDescriptorSet(pRenderer, pDescriptorSetVBShade[0]);
removeDescriptorSet(pRenderer, pDescriptorSetVBShade[1]);
#if !defined(METAL)
removeDescriptorSet(pRenderer, pDescriptorSetVBPass[0]);
removeDescriptorSet(pRenderer, pDescriptorSetVBPass[1]);
#endif
removeDescriptorSet(pRenderer, pDescriptorSetLightClusters[0]);
removeDescriptorSet(pRenderer, pDescriptorSetLightClusters[1]);
removeDescriptorSet(pRenderer, pDescriptorSetTriangleFiltering[0]);
removeDescriptorSet(pRenderer, pDescriptorSetTriangleFiltering[1]);
#if defined(METAL)
removeDescriptorSet(pRenderer, pDescriptorSetGodRayPassSampler);
#endif
}
void prepareDescriptorSets()
{
// Triangle Filtering
{
uint64_t size = BATCH_COUNT * sizeof(SmallBatchData);
#if defined(METAL)
const uint32_t paramsCount = 10;
#else
const uint32_t paramsCount = 5;
#endif
DescriptorData filterParams[paramsCount] = {};
filterParams[0].pName = "vertexDataBuffer";
filterParams[0].ppBuffers = &pGeom->pVertexBuffers[0];
filterParams[1].pName = "indexDataBuffer";
filterParams[1].ppBuffers = &pGeom->pIndexBuffer;
filterParams[2].pName = "meshConstantsBuffer";
filterParams[2].ppBuffers = &pMeshConstantsBuffer;
filterParams[3].pName = "materialProps";
filterParams[3].ppBuffers = &pMaterialPropertyBuffer;
filterParams[4].pName = "batchData_rootcbv";
filterParams[4].ppBuffers = &pFilterBatchDataBuffer->pBuffer;
filterParams[4].pSizes = &size;
#if defined(METAL)
// icb data
filterParams[5].pName = "vertexTexCoord";
filterParams[5].ppBuffers = &pGeom->pVertexBuffers[1];
filterParams[6].pName = "vertexTangent";
filterParams[6].ppBuffers = &pGeom->pVertexBuffers[3];
filterParams[7].pName = "vertexNormal";
filterParams[7].ppBuffers = &pGeom->pVertexBuffers[2];
filterParams[8].pName = "drawIDs";
filterParams[8].ppBuffers = &pDrawIDBuffer;
filterParams[9].pName = "texturesArgBuffer";
filterParams[9].mExtractBuffer = true;
filterParams[9].ppDescriptorSet = &pDescriptorSetDeferredPass[0];
filterParams[9].mDescriptorSetBufferIndex = 0;
#endif
updateDescriptorSet(pRenderer, 0, pDescriptorSetTriangleFiltering[0], paramsCount, filterParams);
for (uint32_t i = 0; i < gImageCount; ++i)
{
DescriptorData clearParams[3] = {};
clearParams[0].pName = "indirectDrawArgsBufferAlpha";
clearParams[0].mCount = gNumViews;
clearParams[0].ppBuffers = pFilteredIndirectDrawArgumentsBuffer[i][GEOMSET_ALPHATESTED];
clearParams[1].pName = "indirectDrawArgsBufferNoAlpha";
clearParams[1].mCount = gNumViews;
clearParams[1].ppBuffers = pFilteredIndirectDrawArgumentsBuffer[i][GEOMSET_OPAQUE];
clearParams[2].pName = "uncompactedDrawArgsRW";
clearParams[2].mCount = gNumViews;
clearParams[2].ppBuffers = pUncompactedDrawArgumentsBuffer[i];
updateDescriptorSet(pRenderer, i * gNumStages + 0, pDescriptorSetTriangleFiltering[1], 3, clearParams);
DescriptorData filterParams[3] = {};
filterParams[0].pName = "filteredIndicesBuffer";
filterParams[0].mCount = gNumViews;
filterParams[0].ppBuffers = pFilteredIndexBuffer[i];
filterParams[1].pName = "uncompactedDrawArgsRW";
filterParams[1].mCount = gNumViews;
filterParams[1].ppBuffers = pUncompactedDrawArgumentsBuffer[i];
filterParams[2].pName = "uniforms";
filterParams[2].ppBuffers = &pPerFrameUniformBuffers[i];
updateDescriptorSet(pRenderer, i * gNumStages + 1, pDescriptorSetTriangleFiltering[1], 3, filterParams);
DescriptorData compactParams[4] = {};
compactParams[0].pName = "indirectMaterialBuffer";
compactParams[0].ppBuffers = &pFilterIndirectMaterialBuffer[i];
compactParams[1].pName = "indirectDrawArgsBufferAlpha";
compactParams[1].mCount = gNumViews;
compactParams[1].ppBuffers = pFilteredIndirectDrawArgumentsBuffer[i][GEOMSET_ALPHATESTED];
compactParams[2].pName = "indirectDrawArgsBufferNoAlpha";
compactParams[2].mCount = gNumViews;
compactParams[2].ppBuffers = pFilteredIndirectDrawArgumentsBuffer[i][GEOMSET_OPAQUE];
compactParams[3].pName = "uncompactedDrawArgs";
compactParams[3].mCount = gNumViews;
compactParams[3].ppBuffers = pUncompactedDrawArgumentsBuffer[i];
updateDescriptorSet(pRenderer, i * gNumStages + 2, pDescriptorSetTriangleFiltering[1], 4, compactParams);
#if defined(METAL)
Buffer* indexBuffersForStages[2] = { pGeom->pIndexBuffer, pGeom->pIndexBuffer };
Buffer* materialBuffersForStages[2] = { pIndirectMaterialBufferAll, pIndirectMaterialBufferAll };
Buffer* indirectDrawBuffersAlpha[2] = { pIndirectDrawArgumentsBufferAll[GEOMSET_ALPHATESTED], pIndirectDrawArgumentsBufferAll[GEOMSET_ALPHATESTED] };
Buffer* indirectDrawBuffersNoAlpha[2] = { pIndirectDrawArgumentsBufferAll[GEOMSET_OPAQUE], pIndirectDrawArgumentsBufferAll[GEOMSET_OPAQUE] };
for (uint32_t f = 0; f < 2; ++f) // descriptors for FILTERED and UNFILTERED mode
{
for (uint32_t r = 0; r < 2; ++r) // descriptors for VB and DEFERRED stages
{
DescriptorData icbParams[10] = {};
icbParams[0].pName = "indirectDrawArgsBufferAlphaICB";
icbParams[0].mCount = gNumViews;
icbParams[0].ppBuffers = (f == 1) ? pFilteredIndirectDrawArgumentsBuffer[i][GEOMSET_ALPHATESTED] : indirectDrawBuffersAlpha;
icbParams[1].pName = "indirectDrawArgsBufferNoAlphaICB";
icbParams[1].mCount = gNumViews;
icbParams[1].ppBuffers = (f == 1) ? pFilteredIndirectDrawArgumentsBuffer[i][GEOMSET_OPAQUE] : indirectDrawBuffersNoAlpha;
icbParams[2].pName = "uncompactedDrawArgsRW";
icbParams[2].mCount = gNumViews;
icbParams[2].ppBuffers = pUncompactedDrawArgumentsBuffer[i];
icbParams[3].pName = "filteredIndicesBufferICB";
icbParams[3].mCount = gNumViews;
icbParams[3].ppBuffers = (f == 1) ? pFilteredIndexBuffer[i] : indexBuffersForStages;
icbParams[4].pName = "indirectMaterialBufferICB";
icbParams[4].ppBuffers = (f == 1) ? &pFilterIndirectMaterialBuffer[i] : materialBuffersForStages;
icbParams[5].pName = "uniforms";
icbParams[5].ppBuffers = &pPerFrameUniformBuffers[i];
icbParams[6].pName = "icbContainerShadow";
icbParams[6].ppBuffers = &pIndirectCommandBufferShadow[i];
icbParams[7].pName = "icbContainerCamera";
icbParams[7].ppBuffers = &pIndirectCommandBufferCamera[i];
icbParams[8].pName = "piplineStatesShadow";
icbParams[8].mCount = gNumGeomSets;
icbParams[8].ppPipelines = pPipelineShadowPass;
icbParams[9].pName = "piplineStatesCamera";
icbParams[9].mCount = gNumGeomSets;
icbParams[9].ppPipelines = (r == 1) ? pPipelineDeferredPass : pPipelineVisibilityBufferPass;
updateDescriptorSet(pRenderer, i * gNumStages + (3 + (f * 2) + r), pDescriptorSetTriangleFiltering[1], 10, icbParams);
}
}
#endif
}
}
// Light Clustering
{
DescriptorData params[3] = {};
params[0].pName = "lights";
params[0].ppBuffers = &pLightsBuffer;
updateDescriptorSet(pRenderer, 0, pDescriptorSetLightClusters[0], 1, params);
for (uint32_t i = 0; i < gImageCount; ++i)
{
params[0].pName = "lightClustersCount";
params[0].ppBuffers = &pLightClustersCount[i];
params[1].pName = "lightClusters";
params[1].ppBuffers = &pLightClusters[i];
params[2].pName = "uniforms";
params[2].ppBuffers = &pPerFrameUniformBuffers[i];
updateDescriptorSet(pRenderer, i, pDescriptorSetLightClusters[1], 3, params);
}
}
#if !defined(METAL)
// VB, Shadow
{
DescriptorData params[2] = {};
params[0].pName = "diffuseMaps";
params[0].mCount = (uint32_t)gDiffuseMaps.size();
params[0].ppTextures = gDiffuseMaps.data();
updateDescriptorSet(pRenderer, 0, pDescriptorSetVBPass[0], 1, params);
params[0] = {};
for (uint32_t i = 0; i < gImageCount; ++i)
{
for (uint32_t j = 0; j < 2; ++j)
{
params[0].pName = "indirectMaterialBuffer";
params[0].ppBuffers = j == 0 ? &pFilterIndirectMaterialBuffer[i] : &pIndirectMaterialBufferAll;
params[1].pName = "uniforms";
params[1].ppBuffers = &pPerFrameUniformBuffers[i];
updateDescriptorSet(pRenderer, i * 2 + j, pDescriptorSetVBPass[1], 2, params);
}
}
}
#endif
// VB Shade
{
DescriptorData vbShadeParams[12] = {};
DescriptorData vbShadeParamsPerFrame[7] = {};
vbShadeParams[0].pName = "vbTex";
vbShadeParams[0].ppTextures = &pRenderTargetVBPass->pTexture;
vbShadeParams[1].pName = "diffuseMaps";
vbShadeParams[1].mCount = (uint32_t)gDiffuseMapsPacked.size();
vbShadeParams[1].ppTextures = gDiffuseMapsPacked.data();
vbShadeParams[2].pName = "normalMaps";
vbShadeParams[2].mCount = (uint32_t)gNormalMapsPacked.size();
vbShadeParams[2].ppTextures = gNormalMapsPacked.data();
vbShadeParams[3].pName = "specularMaps";
vbShadeParams[3].mCount = (uint32_t)gSpecularMapsPacked.size();
vbShadeParams[3].ppTextures = gSpecularMapsPacked.data();
vbShadeParams[4].pName = "vertexPos";
vbShadeParams[4].ppBuffers = &pGeom->pVertexBuffers[0];
vbShadeParams[5].pName = "vertexTexCoord";
vbShadeParams[5].ppBuffers = &pGeom->pVertexBuffers[1];
vbShadeParams[6].pName = "vertexNormal";
vbShadeParams[6].ppBuffers = &pGeom->pVertexBuffers[2];
vbShadeParams[7].pName = "vertexTangent";
vbShadeParams[7].ppBuffers = &pGeom->pVertexBuffers[3];
vbShadeParams[8].pName = "lights";
vbShadeParams[8].ppBuffers = &pLightsBuffer;
vbShadeParams[9].pName = "aoTex";
vbShadeParams[9].ppTextures = &pRenderTargetAO->pTexture;
vbShadeParams[10].pName = "shadowMap";
vbShadeParams[10].ppTextures = &pRenderTargetShadow->pTexture;
vbShadeParams[11].pName = "meshConstantsBuffer";
vbShadeParams[11].ppBuffers = &pMeshConstantsBuffer;
updateDescriptorSet(pRenderer, 0, pDescriptorSetVBShade[0], 12, vbShadeParams);
for (uint32_t i = 0; i < gImageCount; ++i)
{
vbShadeParamsPerFrame[0].pName = "lightClustersCount";
vbShadeParamsPerFrame[0].ppBuffers = &pLightClustersCount[i];
vbShadeParamsPerFrame[1].pName = "lightClusters";
vbShadeParamsPerFrame[1].ppBuffers = &pLightClusters[i];
vbShadeParamsPerFrame[2].pName = "uniforms";
vbShadeParamsPerFrame[2].ppBuffers = &pPerFrameUniformBuffers[i];
Buffer* pIndirectBuffers[gNumGeomSets] = { NULL };
for (uint32_t g = 0; g < gNumGeomSets; ++g)
{
pIndirectBuffers[g] = pFilteredIndirectDrawArgumentsBuffer[i][g][VIEW_CAMERA];
}
for (uint32_t j = 0; j < 2; ++j)
{
vbShadeParamsPerFrame[3].pName = "indirectMaterialBuffer";
vbShadeParamsPerFrame[3].ppBuffers =
j == 0 ? &pFilterIndirectMaterialBuffer[i] : &pIndirectMaterialBufferAll;
vbShadeParamsPerFrame[4].pName = "filteredIndexBuffer";
vbShadeParamsPerFrame[4].ppBuffers = j == 0 ? &pFilteredIndexBuffer[i][VIEW_CAMERA] : &pGeom->pIndexBuffer;
#if defined(ORBIS) || defined(PROSPERO)
vbShadeParamsPerFrame[5].pName = "indirectDrawArgsOpaque";
vbShadeParamsPerFrame[5].ppBuffers = j == 0 ? &pIndirectBuffers[GEOMSET_OPAQUE] : &pIndirectDrawArgumentsBufferAll[GEOMSET_OPAQUE];
vbShadeParamsPerFrame[6].pName = "indirectDrawArgsAlpha";
vbShadeParamsPerFrame[6].ppBuffers = j == 0 ? &pIndirectBuffers[GEOMSET_ALPHATESTED] : &pIndirectDrawArgumentsBufferAll[GEOMSET_ALPHATESTED];
updateDescriptorSet(pRenderer, i * 2 + j, pDescriptorSetVBShade[1], 7, vbShadeParamsPerFrame);
#else
vbShadeParamsPerFrame[5].pName = "indirectDrawArgs";
vbShadeParamsPerFrame[5].mCount = gNumGeomSets;
vbShadeParamsPerFrame[5].ppBuffers = j == 0 ? pIndirectBuffers : pIndirectDrawArgumentsBufferAll;
updateDescriptorSet(pRenderer, i * 2 + j, pDescriptorSetVBShade[1], 6, vbShadeParamsPerFrame);
#endif
}
}
}
// Deferred Pass
{
DescriptorData params[6] = {};
params[0].pName = "diffuseMaps";
params[0].mCount = (uint32_t)gDiffuseMaps.size();
params[0].ppTextures = gDiffuseMaps.data();
params[1].pName = "normalMaps";
params[1].mCount = (uint32_t)gNormalMaps.size();
params[1].ppTextures = gNormalMaps.data();
params[2].pName = "specularMaps";
params[2].mCount = (uint32_t)gSpecularMaps.size();
params[2].ppTextures = gSpecularMaps.data();
params[3].pName = "meshConstantsBuffer";
params[3].ppBuffers = &pMeshConstantsBuffer;
updateDescriptorSet(pRenderer, 0, pDescriptorSetDeferredPass[0], 4, params);
#if !defined(METAL)
for (uint32_t i = 0; i < gImageCount; ++i)
{
for (uint32_t j = 0; j < 2; ++j)
{
DescriptorData params[2] = {};
params[0].pName = "indirectMaterialBuffer";
params[0].ppBuffers = j == 0 ? &pFilterIndirectMaterialBuffer[i] : &pIndirectMaterialBufferAll;
params[1].pName = "uniforms";
params[1].ppBuffers = &pPerFrameUniformBuffers[i];
updateDescriptorSet(pRenderer, i * 2 + j, pDescriptorSetDeferredPass[1], 2, params);
}
}
#endif
}
// Deferred Shade
{
DescriptorData params[7] = {};
params[0].pName = "gBufferColor";
params[0].ppTextures = &pRenderTargetDeferredPass[DEFERRED_RT_ALBEDO]->pTexture;
params[1].pName = "gBufferNormal";
params[1].ppTextures = &pRenderTargetDeferredPass[DEFERRED_RT_NORMAL]->pTexture;
params[2].pName = "gBufferSpecular";
params[2].ppTextures = &pRenderTargetDeferredPass[DEFERRED_RT_SPECULAR]->pTexture;
params[3].pName = "gBufferSimulation";
params[3].ppTextures = &pRenderTargetDeferredPass[DEFERRED_RT_SIMULATION]->pTexture;
params[4].pName = "gBufferDepth";
params[4].ppTextures = &pDepthBuffer->pTexture;
params[5].pName = "shadowMap";
params[5].ppTextures = &pRenderTargetShadow->pTexture;
params[6].pName = "aoTex";
params[6].ppTextures = &pRenderTargetAO->pTexture;
updateDescriptorSet(pRenderer, 0, pDescriptorSetDeferredShade[0], 7, params);
for (uint32_t i = 0; i < gImageCount; ++i)
{
params[0].pName = "uniforms";
params[0].ppBuffers = &pPerFrameUniformBuffers[i];
updateDescriptorSet(pRenderer, i, pDescriptorSetDeferredShade[1], 1, params);
}
}
// Deferred Shade Lighting
{
DescriptorData params[7] = {};
params[0].pName = "lights";
params[0].ppBuffers = &pLightsBuffer;
params[1].pName = "gBufferColor";
params[1].ppTextures = &pRenderTargetDeferredPass[DEFERRED_RT_ALBEDO]->pTexture;
params[2].pName = "gBufferNormal";
params[2].ppTextures = &pRenderTargetDeferredPass[DEFERRED_RT_NORMAL]->pTexture;
params[3].pName = "gBufferSpecular";
params[3].ppTextures = &pRenderTargetDeferredPass[DEFERRED_RT_SPECULAR]->pTexture;
params[4].pName = "gBufferSpecular";
params[4].ppTextures = &pRenderTargetDeferredPass[DEFERRED_RT_SPECULAR]->pTexture;
params[5].pName = "gBufferSimulation";
params[5].ppTextures = &pRenderTargetDeferredPass[DEFERRED_RT_SIMULATION]->pTexture;
params[6].pName = "gBufferDepth";
params[6].ppTextures = &pDepthBuffer->pTexture;
updateDescriptorSet(pRenderer, 0, pDescriptorSetDeferredShadePointLight[0], 7, params);
for (uint32_t i = 0; i < gImageCount; ++i)
{
params[0].pName = "uniforms";
params[0].ppBuffers = &pPerFrameUniformBuffers[i];
updateDescriptorSet(pRenderer, i, pDescriptorSetDeferredShadePointLight[1], 1, params);
}
}
// HDAO
{
DescriptorData params[2] = {};
params[0].pName = "g_txDepth";
params[0].ppTextures = &pDepthBuffer->pTexture;
updateDescriptorSet(pRenderer, 0, pDescriptorSetAO, 1, params);
}
// Resolve
{
DescriptorData params[2] = {};
params[0].pName = "msaaSource";
params[0].ppTextures = &pRenderTargetMSAA->pTexture;
updateDescriptorSet(pRenderer, 0, pDescriptorSetResolve, 1, params);
params[0].ppTextures = &pRenderTargetSun->pTexture;
updateDescriptorSet(pRenderer, 1, pDescriptorSetResolve, 1, params);
}
// Sun
{
for (uint32_t i = 0; i < gImageCount; ++i)
{
DescriptorData sunParams[1] = {};
sunParams[0].pName = "UniformBufferSunMatrices";
sunParams[0].ppBuffers = &pUniformBufferSun[i];
updateDescriptorSet(pRenderer, i, pDescriptorSetSunPass, 1, sunParams);
}
}
// God Ray
{
DescriptorData GodrayParams[1] = {};
GodrayParams[0].pName = "uTex0";
#if (MSAASAMPLECOUNT > 1)
GodrayParams[0].ppTextures = &pRenderTargetSunResolved->pTexture;
#else
GodrayParams[0].ppTextures = &pRenderTargetSun->pTexture;
#endif
updateDescriptorSet(pRenderer, 0, pDescriptorSetGodRayPass, 1, GodrayParams);
GodrayParams[0].ppTextures = &pRenderTargetGodRay[0]->pTexture;
updateDescriptorSet(pRenderer, 1, pDescriptorSetGodRayPass, 1, GodrayParams);
GodrayParams[0].ppTextures = &pRenderTargetGodRay[1]->pTexture;
updateDescriptorSet(pRenderer, 2, pDescriptorSetGodRayPass, 1, GodrayParams);
}
// Curve conversion
{
DescriptorData CurveConversionParams[3] = {};
CurveConversionParams[0].pName = "SceneTex";
CurveConversionParams[0].ppTextures = &pIntermediateRenderTarget->pTexture;
CurveConversionParams[1].pName = "GodRayTex";
CurveConversionParams[1].ppTextures = &pRenderTargetGodRay[0]->pTexture;
updateDescriptorSet(pRenderer, 0, pDescriptorSetCurveConversionPass, 2, CurveConversionParams);
CurveConversionParams[1].ppTextures = &pRenderTargetGodRay[1]->pTexture;
updateDescriptorSet(pRenderer, 1, pDescriptorSetCurveConversionPass, 2, CurveConversionParams);
}
// Sky
{
DescriptorData skyParams[1] = {};
skyParams[0].pName = "skyboxTex";
skyParams[0].ppTextures = &pSkybox;
updateDescriptorSet(pRenderer, 0, pDescriptorSetSkybox[0], 1, skyParams);
for (uint32_t i = 0; i < gImageCount; ++i)
{
skyParams[0].pName = "UniformCameraSky";
skyParams[0].ppBuffers = &pUniformBufferSky[i];
updateDescriptorSet(pRenderer, i, pDescriptorSetSkybox[1], 1, skyParams);
}
}
// Present
{
DescriptorData params[3] = {};
params[0].pName = "uTex0";
params[0].ppTextures = &pIntermediateRenderTarget->pTexture;
updateDescriptorSet(pRenderer, 0, pDescriptorSetPresentPass, 1, params);
params[0].ppTextures = &pCurveConversionRenderTarget->pTexture;
updateDescriptorSet(pRenderer, 1, pDescriptorSetPresentPass, 1, params);
}
}
/************************************************************************/
// Add render targets
/************************************************************************/
bool addRenderTargets()
{
const uint32_t width = mSettings.mWidth;
const uint32_t height = mSettings.mHeight;
SwapChainDesc swapChainDesc = {};
swapChainDesc.mWindowHandle = pWindow->handle;
swapChainDesc.mPresentQueueCount = 1;
swapChainDesc.ppPresentQueues = &pGraphicsQueue;
swapChainDesc.mWidth = width;
swapChainDesc.mHeight = height;
swapChainDesc.mImageCount = gImageCount;
if (gAppSettings.mOutputMode == OUTPUT_MODE_HDR10)
swapChainDesc.mColorFormat = TinyImageFormat_R10G10B10A2_UNORM;
else
swapChainDesc.mColorFormat = getRecommendedSwapchainFormat(true);
swapChainDesc.mColorClearValue = {{1, 1, 1, 1}};
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.mDescriptors = DESCRIPTOR_TYPE_TEXTURE;
depthRT.mFormat = TinyImageFormat_D32_SFLOAT;
depthRT.mStartState = RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
depthRT.mHeight = height;
depthRT.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
depthRT.mSampleQuality = 0;
depthRT.mFlags = TEXTURE_CREATION_FLAG_ESRAM;
depthRT.mWidth = width;
depthRT.pName = "Depth Buffer RT";
addRenderTarget(pRenderer, &depthRT, &pDepthBuffer);
/************************************************************************/
// Shadow pass render target
/************************************************************************/
RenderTargetDesc shadowRTDesc = {};
shadowRTDesc.mArraySize = 1;
shadowRTDesc.mClearValue = optimizedDepthClear;
shadowRTDesc.mDepth = 1;
shadowRTDesc.mDescriptors = DESCRIPTOR_TYPE_TEXTURE;
shadowRTDesc.mFormat = TinyImageFormat_D32_SFLOAT;
shadowRTDesc.mStartState = RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
shadowRTDesc.mWidth = gShadowMapSize;
shadowRTDesc.mSampleCount = SAMPLE_COUNT_1;
shadowRTDesc.mSampleQuality = 0;
//shadowRTDesc.mFlags = TEXTURE_CREATION_FLAG_ESRAM;
shadowRTDesc.mHeight = gShadowMapSize;
shadowRTDesc.pName = "Shadow Map RT";
addRenderTarget(pRenderer, &shadowRTDesc, &pRenderTargetShadow);
/************************************************************************/
// Visibility buffer pass render target
/************************************************************************/
RenderTargetDesc vbRTDesc = {};
vbRTDesc.mArraySize = 1;
vbRTDesc.mClearValue = optimizedColorClearWhite;
vbRTDesc.mDepth = 1;
vbRTDesc.mDescriptors = DESCRIPTOR_TYPE_TEXTURE;
vbRTDesc.mFormat = TinyImageFormat_R8G8B8A8_UNORM;
vbRTDesc.mStartState = RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
vbRTDesc.mHeight = height;
vbRTDesc.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
vbRTDesc.mSampleQuality = 0;
vbRTDesc.mFlags = TEXTURE_CREATION_FLAG_ESRAM;
vbRTDesc.mWidth = width;
vbRTDesc.pName = "VB RT";
addRenderTarget(pRenderer, &vbRTDesc, &pRenderTargetVBPass);
/************************************************************************/
// Deferred pass render targets
/************************************************************************/
RenderTargetDesc deferredRTDesc = {};
deferredRTDesc.mArraySize = 1;
deferredRTDesc.mClearValue = optimizedColorClearBlack;
deferredRTDesc.mDepth = 1;
deferredRTDesc.mDescriptors = DESCRIPTOR_TYPE_TEXTURE;
deferredRTDesc.mFormat = TinyImageFormat_R8G8B8A8_UNORM;
deferredRTDesc.mStartState = RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
deferredRTDesc.mHeight = height;
deferredRTDesc.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
deferredRTDesc.mSampleQuality = 0;
deferredRTDesc.mWidth = width;
deferredRTDesc.pName = "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.mDescriptors = DESCRIPTOR_TYPE_TEXTURE;
msaaRTDesc.mFormat = gAppSettings.mOutputMode == OutputMode::OUTPUT_MODE_SDR ? TinyImageFormat_R8G8B8A8_UNORM : TinyImageFormat_R10G10B10A2_UNORM;
msaaRTDesc.mStartState = RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
msaaRTDesc.mHeight = height;
msaaRTDesc.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
msaaRTDesc.mSampleQuality = 0;
msaaRTDesc.mWidth = width;
msaaRTDesc.pName = "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.
#ifndef PROSPERO
msaaRTDesc.mFlags = TEXTURE_CREATION_FLAG_NO_COMPRESSION;
#endif
addRenderTarget(pRenderer, &msaaRTDesc, &pRenderTargetMSAA);
/************************************************************************/
// HDAO render target
/************************************************************************/
RenderTargetDesc aoRTDesc = {};
aoRTDesc.mArraySize = 1;
aoRTDesc.mClearValue = optimizedColorClearBlack;
aoRTDesc.mDepth = 1;
aoRTDesc.mDescriptors = DESCRIPTOR_TYPE_TEXTURE;
aoRTDesc.mFormat = TinyImageFormat_R8_UNORM;
aoRTDesc.mStartState = RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
aoRTDesc.mHeight = height;
aoRTDesc.mSampleCount = SAMPLE_COUNT_1;
aoRTDesc.mSampleQuality = 0;
aoRTDesc.mWidth = width;
aoRTDesc.pName = "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.mDescriptors = DESCRIPTOR_TYPE_TEXTURE;
postProcRTDesc.mFormat = gAppSettings.mOutputMode == OutputMode::OUTPUT_MODE_SDR ? TinyImageFormat_R8G8B8A8_UNORM : TinyImageFormat_R10G10B10A2_UNORM;
postProcRTDesc.mStartState = RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
postProcRTDesc.mHeight = mSettings.mHeight;
postProcRTDesc.mWidth = mSettings.mWidth;
postProcRTDesc.mSampleCount = pSwapChain->ppRenderTargets[0]->mSampleCount;
postProcRTDesc.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
postProcRTDesc.pName = "pIntermediateRenderTarget";
addRenderTarget(pRenderer, &postProcRTDesc, &pIntermediateRenderTarget);
/************************************************************************/
// Setup MSAA resolve pipeline
/************************************************************************/
DepthStateDesc depthStateDisableDesc = {};
RasterizerStateDesc rasterizerStateCullNoneDesc = { CULL_MODE_NONE };
PipelineDesc pipelineDesc = {};
pipelineDesc.pCache = pPipelineCache;
pipelineDesc.mType = PIPELINE_TYPE_GRAPHICS;
GraphicsPipelineDesc& resolvePipelineSettings = pipelineDesc.mGraphicsDesc;
resolvePipelineSettings = { 0 };
resolvePipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
resolvePipelineSettings.mRenderTargetCount = 1;
resolvePipelineSettings.pDepthState = &depthStateDisableDesc;
resolvePipelineSettings.pColorFormats = &pIntermediateRenderTarget->mFormat;
resolvePipelineSettings.mSampleCount = SAMPLE_COUNT_1;
resolvePipelineSettings.mSampleQuality = 0;
resolvePipelineSettings.pRasterizerState = &rasterizerStateCullNoneDesc;
resolvePipelineSettings.pRootSignature = pRootSignatureResolve;
resolvePipelineSettings.pShaderProgram = pShaderResolve;
addPipeline(pRenderer, &pipelineDesc, &pPipelineResolve);
addPipeline(pRenderer, &pipelineDesc, &pPipelineResolvePost);
/************************************************************************/
// GodRay render target
/************************************************************************/
RenderTargetDesc GRRTDesc = {};
GRRTDesc.mArraySize = 1;
GRRTDesc.mClearValue = {{0.0f, 0.0f, 0.0f, 1.0f}};
GRRTDesc.mDepth = 1;
GRRTDesc.mDescriptors = DESCRIPTOR_TYPE_TEXTURE;
GRRTDesc.mFormat = gAppSettings.mOutputMode == OutputMode::OUTPUT_MODE_SDR ? TinyImageFormat_R8G8B8A8_UNORM : TinyImageFormat_R10G10B10A2_UNORM;
GRRTDesc.mStartState = RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
GRRTDesc.mHeight = mSettings.mHeight;
GRRTDesc.mWidth = mSettings.mWidth;
GRRTDesc.mSampleCount = (SampleCount)MSAASAMPLECOUNT;
GRRTDesc.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
GRRTDesc.pName = "Sun RT";
addRenderTarget(pRenderer, &GRRTDesc, &pRenderTargetSun);
GRRTDesc.mSampleCount = pSwapChain->ppRenderTargets[0]->mSampleCount;
GRRTDesc.pName = "Sun Resolve RT";
addRenderTarget(pRenderer, &GRRTDesc, &pRenderTargetSunResolved);
GraphicsPipelineDesc& resolveGodrayPipelineSettings = pipelineDesc.mGraphicsDesc;
resolveGodrayPipelineSettings = { 0 };
resolveGodrayPipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
resolveGodrayPipelineSettings.mRenderTargetCount = 1;
resolveGodrayPipelineSettings.pDepthState = &depthStateDisableDesc;
resolveGodrayPipelineSettings.pColorFormats = &GRRTDesc.mFormat;
resolveGodrayPipelineSettings.mSampleCount = SAMPLE_COUNT_1;
resolveGodrayPipelineSettings.mSampleQuality = 0;
resolveGodrayPipelineSettings.pRasterizerState = &rasterizerStateCullNoneDesc;
resolveGodrayPipelineSettings.pRootSignature = pRootSignatureResolve;
resolveGodrayPipelineSettings.pShaderProgram = pShaderGodrayResolve;
addPipeline(pRenderer, &pipelineDesc, &pPipelineGodrayResolve);
addPipeline(pRenderer, &pipelineDesc, &pPipelineGodrayResolvePost);
GRRTDesc.mHeight = mSettings.mHeight / gGodrayScale;
GRRTDesc.mWidth = mSettings.mWidth / gGodrayScale;
GRRTDesc.mSampleCount = pSwapChain->ppRenderTargets[0]->mSampleCount;
GRRTDesc.mFormat = pSwapChain->ppRenderTargets[0]->mFormat;
GRRTDesc.pName = "GodRay RT A";
addRenderTarget(pRenderer, &GRRTDesc, &pRenderTargetGodRay[0]);
GRRTDesc.pName = "GodRay RT B";
addRenderTarget(pRenderer, &GRRTDesc, &pRenderTargetGodRay[1]);
/************************************************************************/
// Color Conversion render target
/************************************************************************/
RenderTargetDesc postCurveConversionRTDesc = {};
postCurveConversionRTDesc.mArraySize = 1;
postCurveConversionRTDesc.mClearValue = { { 0.0f, 0.0f, 0.0f, 0.0f } };
postCurveConversionRTDesc.mDepth = 1;
postCurveConversionRTDesc.mDescriptors = DESCRIPTOR_TYPE_TEXTURE;
postCurveConversionRTDesc.mFormat = pSwapChain->ppRenderTargets[0]->mFormat;
postCurveConversionRTDesc.mStartState = RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
postCurveConversionRTDesc.mHeight = mSettings.mHeight;
postCurveConversionRTDesc.mWidth = mSettings.mWidth;
postCurveConversionRTDesc.mSampleCount = pSwapChain->ppRenderTargets[0]->mSampleCount;
postCurveConversionRTDesc.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
postCurveConversionRTDesc.pName = "pCurveConversionRenderTarget";
addRenderTarget(pRenderer, &postCurveConversionRTDesc, &pCurveConversionRenderTarget);
/************************************************************************/
/************************************************************************/
ENDALLOCATION("RTs");
return true;
}
void removeRenderTargets()
{
removeRenderTarget(pRenderer, pCurveConversionRenderTarget);
removeRenderTarget(pRenderer, pRenderTargetSun);
removeRenderTarget(pRenderer, pRenderTargetSunResolved);
removeRenderTarget(pRenderer, pRenderTargetGodRay[0]);
removeRenderTarget(pRenderer, pRenderTargetGodRay[1]);
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()
{
char sampleCountMacroBuffer[64] = {};
char useAoMacroBuffer[2][64] = {};
char hdaoMacroBuffer[4][64] = {};
sprintf(sampleCountMacroBuffer, "%d", MSAASAMPLECOUNT);
sprintf(useAoMacroBuffer[0], "%d", 0);
sprintf(useAoMacroBuffer[1], "%d", 1);
ShaderMacro shadingMacros[2][2] = {
{ { "SAMPLE_COUNT", sampleCountMacroBuffer }, { "USE_AMBIENT_OCCLUSION", "" } },
{ { "SAMPLE_COUNT", sampleCountMacroBuffer }, { "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 = {};
ShaderLoadDesc batchCompaction = {};
ShaderLoadDesc clearLights = {};
ShaderLoadDesc clusterLights = {};
#if defined(METAL)
ShaderLoadDesc icbGeneratorShaderDesc = {};
icbGeneratorShaderDesc.mStages[0] = { "icb.comp", NULL, 0 };
addShader(pRenderer, &icbGeneratorShaderDesc, &pShaderICBGenerator);
#endif
shadowPass.mStages[0] = { "shadow_pass.vert", NULL, 0 };
shadowPassAlpha.mStages[0] = { "shadow_pass_alpha.vert", NULL, 0 };
shadowPassAlpha.mStages[1] = { "shadow_pass_alpha.frag", NULL, 0 };
vbPass.mStages[0] = { "visibilityBuffer_pass.vert", NULL, 0, NULL, SHADER_STAGE_LOAD_FLAG_ENABLE_PS_PRIMITIVEID };
vbPass.mStages[1] = { "visibilityBuffer_pass.frag", NULL, 0, NULL, SHADER_STAGE_LOAD_FLAG_ENABLE_PS_PRIMITIVEID };
vbPassAlpha.mStages[0] = { "visibilityBuffer_pass_alpha.vert", NULL, 0, NULL, SHADER_STAGE_LOAD_FLAG_ENABLE_PS_PRIMITIVEID };
vbPassAlpha.mStages[1] = { "visibilityBuffer_pass_alpha.frag", NULL, 0, NULL, SHADER_STAGE_LOAD_FLAG_ENABLE_PS_PRIMITIVEID };
#if defined(ORBIS) || defined(PROSPERO)
// No SV_PrimitiveID in pixel shader on ORBIS. Only available in gs stage so we need
// a passthrough gs
vbPass.mStages[2] = { "visibilityBuffer_pass.geom", NULL, 0 };
vbPassAlpha.mStages[2] = { "visibilityBuffer_pass_alpha.geom", NULL, 0 };
#endif
deferredPass.mStages[0] = { "deferred_pass.vert", NULL, 0 };
deferredPass.mStages[1] = { "deferred_pass.frag", NULL, 0 };
deferredPassAlpha.mStages[0] = { "deferred_pass.vert", NULL, 0 };
deferredPassAlpha.mStages[1] = { "deferred_pass_alpha.frag", NULL, 0 };
for (uint32_t i = 0; i < 2; ++i)
{
shadingMacros[i][1].value = useAoMacroBuffer[i]; //USE_AMBIENT_OCCLUSION
vbShade[i].mStages[0] = { "visibilityBuffer_shade.vert", NULL, 0 };
vbShade[i].mStages[1] = { "visibilityBuffer_shade.frag", shadingMacros[i], 2 };
deferredShade[i].mStages[0] = { "deferred_shade.vert", NULL, 0 };
deferredShade[i].mStages[1] = { "deferred_shade.frag", shadingMacros[i], 2 };
}
deferredPointlights.mStages[0] = { "deferred_shade_pointlight.vert", shadingMacros[0], 1 };
deferredPointlights.mStages[1] = { "deferred_shade_pointlight.frag", shadingMacros[0], 1 };
// Resolve shader
resolvePass.mStages[0] = { "resolve.vert", shadingMacros[0], 1 };
resolvePass.mStages[1] = { "resolve.frag", shadingMacros[0], 1 };
// Resolve shader
resolveGodrayPass.mStages[0] = { "resolve.vert", shadingMacros[0], 1 };
resolveGodrayPass.mStages[1] = { "resolveGodray.frag", shadingMacros[0], 1 };
// HDAO post-process shader
for (uint32_t i = 0; i < 4; ++i)
{
sprintf(hdaoMacroBuffer[i], "%u", (i + 1));
hdaoMacros[i][0] = shadingMacros[0][0];
hdaoMacros[i][1] = { "AO_QUALITY", hdaoMacroBuffer[i] };
ao[i].mStages[0] = { "HDAO.vert", hdaoMacros[i], 2 };
ao[i].mStages[1] = { "HDAO.frag", hdaoMacros[i], 2 };
}