Permalink
Cannot retrieve contributors at this time
/* | |
* 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 }; | |
} | |