// This file is part of the FidelityFX SDK. // // Copyright (C) 2024 Advanced Micro Devices, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files(the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and /or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions : // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include "brixelizergirendermodule.h" #include #include #include "core/backend_interface.h" #include "core/components/meshcomponent.h" #include "core/components/animationcomponent.h" #include "core/scene.h" #include "core/loaders/textureloader.h" #include "render/device.h" #include "render/dynamicresourcepool.h" #include "render/profiler.h" #include "render/rootsignature.h" #include "render/parameterset.h" #include "render/pipelineobject.h" #include "shaders/surfacerendercommon.h" #include "shaders/lightingcommon.h" using namespace std::experimental; using namespace cauldron; constexpr uint32_t g_NumNoiseTextures = 16; struct GIConstants { float DiffuseGIFactor; float SpecularGIFactor; int MultiBounce; int pad1; }; void BrixelizerGIRenderModule::Init(const json& initData) { m_PrevProjection = Mat4::Matrix4(0.0f); m_pColorTarget = GetFramework()->GetColorTargetForCallback(GetName()); m_pDiffuseTexture = GetFramework()->GetRenderTexture(L"GBufferAlbedoRT"); m_pDepthBuffer = GetFramework()->GetRenderTexture(L"DepthTarget"); m_pNormalTarget = GetFramework()->GetRenderTexture(L"GBufferNormalRT"); m_pVelocityBuffer = GetFramework()->GetRenderTexture(L"GBufferMotionVectorRT"); m_pRoughnessTarget = GetFramework()->GetRenderTexture(L"GBufferAoRoughnessMetallicRT"); m_pHistoryLitOutput = GetFramework()->GetRenderTexture(L"HistoryLitOutput"); m_pHistoryDepth = GetFramework()->GetRenderTexture(L"HistoryDepth"); m_pHistoryNormals = GetFramework()->GetRenderTexture(L"HistoryNormals"); m_pDiffuseGI = GetFramework()->GetRenderTexture(L"DiffuseGI"); m_pSpecularGI = GetFramework()->GetRenderTexture(L"SpecularGI"); m_pDebugVisualization = GetFramework()->GetRenderTexture(L"DebugVisualization"); m_pLitOutputCopy = GetFramework()->GetRenderTexture(L"LitOutputCopy"); // Create SDF atlas texture { TextureDesc desc = {}; desc.Format = ResourceFormat::R8_UNORM; desc.Flags = ResourceFlags::AllowUnorderedAccess; desc.Width = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; desc.Height = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; desc.DepthOrArraySize = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; desc.Dimension = TextureDimension::Texture3D; desc.MipLevels = 1; desc.Name = L"Brixelizer SDF Atlas"; m_pSdfAtlas = GetDynamicResourcePool()->CreateTexture(&desc, ResourceState::PixelShaderResource | ResourceState::NonPixelShaderResource); } // Create brick AABBs buffer { BufferDesc desc = {}; desc.Type = BufferType::Data; desc.Flags = ResourceFlags::AllowUnorderedAccess; desc.Size = FFX_BRIXELIZER_BRICK_AABBS_SIZE; desc.Alignment = 0; desc.Stride = FFX_BRIXELIZER_BRICK_AABBS_STRIDE; desc.Name = L"Brixelizer Brick AABB List"; m_pBrickAABBs = GetDynamicResourcePool()->CreateBuffer(&desc, ResourceState::CommonResource); } // Create cascade AABB trees for (uint32_t i = 0; i < _countof(m_pCascadeAABBTrees); ++i) { wchar_t name[64] = {}; swprintf(name, _countof(name), L"Brixelizer Cascade[%u] AABB Tree", i); BufferDesc desc = {}; desc.Type = BufferType::Data; desc.Flags = ResourceFlags::AllowUnorderedAccess; desc.Size = FFX_BRIXELIZER_CASCADE_AABB_TREE_SIZE; desc.Alignment = 0; desc.Stride = FFX_BRIXELIZER_CASCADE_AABB_TREE_STRIDE; desc.Name = name; m_pCascadeAABBTrees[i] = GetDynamicResourcePool()->CreateBuffer(&desc, ResourceState::CommonResource); } // Create cascade brick maps for (uint32_t i = 0; i < _countof(m_pCascadeBrickMaps); ++i) { wchar_t name[64] = {}; swprintf(name, _countof(name), L"Brixelizer Cascade[%u] Brick Map", i); BufferDesc desc = {}; desc.Type = BufferType::Data; desc.Flags = ResourceFlags::AllowUnorderedAccess; desc.Size = FFX_BRIXELIZER_CASCADE_BRICK_MAP_SIZE; desc.Alignment = 0; desc.Stride = FFX_BRIXELIZER_CASCADE_BRICK_MAP_STRIDE; desc.Name = name; m_pCascadeBrickMaps[i] = GetDynamicResourcePool()->CreateBuffer(&desc, ResourceState::CommonResource); } // Create scratch buffer { BufferDesc desc = {}; desc.Type = BufferType::Data; desc.Flags = ResourceFlags::AllowUnorderedAccess; desc.Size = GPU_SCRATCH_BUFFER_SIZE; desc.Alignment = 0; desc.Name = L"Scratch Buffer"; m_pGpuScratchBuffer = GetDynamicResourcePool()->CreateBuffer(&desc, ResourceState::CommonResource); } // Create example shader { SamplerDesc sdfAtlasSampler; sdfAtlasSampler.Filter = FilterFunc::MinMagLinearMipPoint; sdfAtlasSampler.AddressU = AddressMode::Wrap; sdfAtlasSampler.AddressV = AddressMode::Wrap; sdfAtlasSampler.AddressW = AddressMode::Wrap; RootSignatureDesc rootSigDesc; rootSigDesc.AddConstantBufferView(0, ShaderBindStage::Compute, 1); rootSigDesc.AddConstantBufferView(1, ShaderBindStage::Compute, 1); rootSigDesc.AddStaticSamplers(0, ShaderBindStage::Compute, 1, &sdfAtlasSampler); rootSigDesc.AddBufferSRVSet(0, ShaderBindStage::Compute, 1); rootSigDesc.AddTextureSRVSet(1, ShaderBindStage::Compute, 1); rootSigDesc.AddBufferSRVSet(2, ShaderBindStage::Compute, 24); rootSigDesc.AddBufferSRVSet(26, ShaderBindStage::Compute, 24); rootSigDesc.AddTextureUAVSet(0, ShaderBindStage::Compute, 1); m_pExampleRootSignature = RootSignature::CreateRootSignature(L"BrixelizerExamplePass_RootSignature", rootSigDesc); m_pExampleParameterSet = ParameterSet::CreateParameterSet(m_pExampleRootSignature); m_pExampleParameterSet->SetRootConstantBufferResource(GetDynamicBufferPool()->GetResource(), sizeof(BrixelizerExampleConstants), 0); m_pExampleParameterSet->SetRootConstantBufferResource(GetDynamicBufferPool()->GetResource(), sizeof(FfxBrixelizerContextInfo), 1); DefineList defineList; defineList.insert(std::make_pair(L"FFX_GPU", L"1")); defineList.insert(std::make_pair(L"FFX_HLSL", L"1")); defineList.insert(std::make_pair(L"FFX_HALF", L"1")); PipelineDesc pipelineDesc; pipelineDesc.SetRootSignature(m_pExampleRootSignature); pipelineDesc.AddShaderDesc(ShaderBuildDesc::Compute(L"brixelizergiexample.hlsl", L"MainCS", ShaderModel::SM6_0, &defineList)); m_pExamplePipeline = PipelineObject::CreatePipelineObject(L"BrixelizerExamplePass_PipelineObj", pipelineDesc); } // Create copy lit output shader { RootSignatureDesc rootSigDesc; rootSigDesc.AddTextureSRVSet(0, ShaderBindStage::Compute, 1); rootSigDesc.AddTextureUAVSet(0, ShaderBindStage::Compute, 1); m_pPassThroughRootSignature = RootSignature::CreateRootSignature(L"BrixelizerGICopyHistoryPass_RootSignature", rootSigDesc); m_pPassThroughParameterSet = ParameterSet::CreateParameterSet(m_pPassThroughRootSignature); DefineList defineList; PipelineDesc pipelineDesc; pipelineDesc.SetRootSignature(m_pPassThroughRootSignature); pipelineDesc.AddShaderDesc(ShaderBuildDesc::Compute(L"copytexture.hlsl", L"CopyTextureCS", ShaderModel::SM6_0, &defineList)); m_pPassThroughPipeline = PipelineObject::CreatePipelineObject(L"BrixelizerGICopyHistoryPass_PipelineObj", pipelineDesc); } // Deferred Lighting { // Root Signature RootSignatureDesc signatureDesc; signatureDesc.AddConstantBufferView(0, ShaderBindStage::Compute, 1); // scene information signatureDesc.AddConstantBufferView(1, ShaderBindStage::Compute, 1); // scene lighting information signatureDesc.AddConstantBufferView(2, ShaderBindStage::Compute, 1); // IBL factor signatureDesc.AddTextureSRVSet(0, ShaderBindStage::Compute, 1); // diffuse signatureDesc.AddTextureSRVSet(1, ShaderBindStage::Compute, 1); // normal signatureDesc.AddTextureSRVSet(2, ShaderBindStage::Compute, 1); // specular roughness signatureDesc.AddTextureSRVSet(3, ShaderBindStage::Compute, 1); // depth signatureDesc.AddTextureSRVSet(4, ShaderBindStage::Compute, 1); // brdfTexture signatureDesc.AddTextureSRVSet(5, ShaderBindStage::Compute, 1); // irradianceCube signatureDesc.AddTextureSRVSet(6, ShaderBindStage::Compute, 1); // prefilteredCube signatureDesc.AddTextureSRVSet(7, ShaderBindStage::Compute, MAX_SHADOW_MAP_TEXTURES_COUNT); // shadow maps signatureDesc.AddTextureUAVSet(0, ShaderBindStage::Compute, 1); // ColorTarget output signatureDesc.AddTextureUAVSet(1, ShaderBindStage::Compute, 1); // DiffuseColorTarget output SamplerDesc pointSampler; // default is enough pointSampler.Filter = FilterFunc::MinMagMipPoint; std::vector samplers; samplers.push_back(pointSampler); signatureDesc.AddStaticSamplers(0, ShaderBindStage::Compute, static_cast(samplers.size()), samplers.data()); static bool s_InvertedDepth = GetConfig()->InvertedDepth; SamplerDesc comparisonSampler; comparisonSampler.Comparison = s_InvertedDepth ? ComparisonFunc::GreaterEqual : ComparisonFunc::LessEqual; comparisonSampler.Filter = FilterFunc::ComparisonMinMagLinearMipPoint; comparisonSampler.MaxAnisotropy = 1; samplers.clear(); samplers.push_back(comparisonSampler); signatureDesc.AddStaticSamplers(1, ShaderBindStage::Compute, static_cast(samplers.size()), samplers.data()); // Setup samplers for brdfTexture, irradianceCube and prefilteredCube SamplerDesc brdfSampler; brdfSampler.AddressW = AddressMode::Wrap; brdfSampler.Filter = FilterFunc::MinMagMipLinear; brdfSampler.MaxAnisotropy = 1; samplers.clear(); samplers.push_back(brdfSampler); signatureDesc.AddStaticSamplers(2, ShaderBindStage::Compute, static_cast(samplers.size()), samplers.data()); m_pDeferredLightingRootSignature = RootSignature::CreateRootSignature(L"LightingRenderModule_RootSignature", signatureDesc); // Setup the pipeline object PipelineDesc psoDesc; psoDesc.SetRootSignature(m_pDeferredLightingRootSignature); DefineList defineList; // Setup the shaders to build on the pipeline object std::wstring shaderPath = L"lightinggi.hlsl"; psoDesc.AddShaderDesc(ShaderBuildDesc::Compute(shaderPath.c_str(), L"MainCS", ShaderModel::SM6_0, &defineList)); m_pDeferredLightingPipeline = PipelineObject::CreatePipelineObject(L"LightingRenderModule_PipelineObj", psoDesc); // Create parameter set to bind constant buffer and texture m_pDeferredLightingParameterSet = ParameterSet::CreateParameterSet(m_pDeferredLightingRootSignature); // Update necessary scene frame information m_pDeferredLightingParameterSet->SetRootConstantBufferResource(GetDynamicBufferPool()->GetResource(), sizeof(SceneInformation), 0); m_pDeferredLightingParameterSet->SetRootConstantBufferResource(GetDynamicBufferPool()->GetResource(), sizeof(SceneLightingInformation), 1); m_pDeferredLightingParameterSet->SetRootConstantBufferResource(GetDynamicBufferPool()->GetResource(), sizeof(GIConstants), 2); m_pDeferredLightingParameterSet->SetTextureSRV(m_pDiffuseTexture, ViewDimension::Texture2D, 0); m_pDeferredLightingParameterSet->SetTextureSRV(m_pNormalTarget, ViewDimension::Texture2D, 1); m_pDeferredLightingParameterSet->SetTextureSRV(m_pRoughnessTarget, ViewDimension::Texture2D, 2); m_pDeferredLightingParameterSet->SetTextureSRV(m_pDepthBuffer, ViewDimension::Texture2D, 3); m_pDeferredLightingParameterSet->SetTextureSRV(m_pDiffuseGI, ViewDimension::Texture2D, 5); m_pDeferredLightingParameterSet->SetTextureSRV(m_pSpecularGI, ViewDimension::Texture2D, 6); m_pDeferredLightingParameterSet->SetTextureUAV(m_pColorTarget, ViewDimension::Texture2D, 0); m_pDeferredLightingParameterSet->SetTextureUAV(m_pLitOutputCopy, ViewDimension::Texture2D, 1); ShadowMapResourcePool* pShadowMapResourcePool = GetFramework()->GetShadowMapResourcePool(); for (uint32_t i = 0; i < pShadowMapResourcePool->GetRenderTargetCount(); ++i) { m_pDeferredLightingParameterSet->SetTextureSRV(pShadowMapResourcePool->GetRenderTarget(i), ViewDimension::Texture2D, 7 + i); } } // Setup Cauldron FidelityFX interface. const size_t scratchBufferSize = SDKWrapper::ffxGetScratchMemorySize(2); void* scratchBuffer = malloc(scratchBufferSize); memset(scratchBuffer, 0, scratchBufferSize); FfxErrorCode errorCode = SDKWrapper::ffxGetInterface(&m_InitializationParameters.backendInterface, GetDevice(), scratchBuffer, scratchBufferSize, 2); CauldronAssert(ASSERT_CRITICAL, errorCode == FFX_OK, L"Could not initialize the FidelityFX SDK backend"); if (errorCode == FFX_OK) { CauldronAssert(ASSERT_CRITICAL, m_InitializationParameters.backendInterface.fpGetSDKVersion(&m_InitializationParameters.backendInterface) == FFX_SDK_MAKE_VERSION(1, 1, 2), L"FidelityFX Brixelizer GI sample requires linking with a 1.1.2 version SDK backend."); } CreateBrixelizerContext(); CreateBrixelizerGIContext(); GetContentManager()->AddContentListener(this); SetModuleEnabled(true); UISection* uiSection = GetUIManager()->RegisterUIElements("FFX Brixelizer GI", UISectionType::Sample); InitUI(uiSection); TextureLoadCompletionCallbackFn CompletionCallback = [this](const std::vector& textures, void* additionalParams = nullptr) { this->TextureLoadComplete(textures, additionalParams); }; // Load all noise textures. for (int i = 0; i < g_NumNoiseTextures; i++) { filesystem::path noiseTexturePath = filesystem::path("../media/Textures/Noise/LDR_RG01_" + std::to_string(i) + ".png"); GetContentManager()->LoadTexture(TextureLoadInfo(noiseTexturePath), CompletionCallback); } GetFramework()->ConfigureRuntimeShaderRecompiler( // Pre reload callback [this]() { DeleteInstances(); DeleteBrixelizerGIContext(); DeleteBrixelizerContext(); }, // Post reload callback [this]() { CreateBrixelizerContext(); CreateBrixelizerGIContext(); m_Buffers.clear(); FlushInstances(true); }); } BrixelizerGIRenderModule::~BrixelizerGIRenderModule() { DeleteBrixelizerGIContext(); DeleteBrixelizerContext(); free(m_InitializationParameters.backendInterface.scratchBuffer); delete m_pExampleRootSignature; delete m_pExampleParameterSet; delete m_pExamplePipeline; delete m_pPassThroughRootSignature; delete m_pPassThroughPipeline; delete m_pPassThroughParameterSet; delete m_pDeferredLightingRootSignature; delete m_pDeferredLightingParameterSet; delete m_pDeferredLightingPipeline; } void BrixelizerGIRenderModule::EnableModule(bool enabled) { RenderModule::EnableModule(enabled); UpdateUIElementVisibility(); } void BrixelizerGIRenderModule::Execute(double deltaTime, CommandList* pCmdList) { std::lock_guard pipelineLock(m_CriticalSection); GPUScopedProfileCapture sampleMarker(pCmdList, L"Brixelizer GI"); // Recreate the Brixelizer context if voxel size has been changed. if (m_InitializationParameters.cascadeDescs[1].voxelSize != m_MeshUnitSize * m_CascadeSizeRatio) RecreateBrixelizerContext(); if (m_InitColorHistory) { DeferredLighting(pCmdList, false); CopyHistoryResources(pCmdList); m_InitColorHistory = false; } UpdateUIElementVisibility(); UpdateConfig(); // Create the dynamic instances every frame. FlushInstances(false); // Dispatch Brixelizer workloads. UpdateBrixelizerContext(pCmdList); // Restore the Cauldron resource view heaps. SetAllResourceViewHeaps(pCmdList); UpdateBrixelizerGIContext(pCmdList); SetAllResourceViewHeaps(pCmdList); CopyHistoryResources(pCmdList); if (m_OutputMode != OutputMode::DebugVisualization) { DeferredLighting(pCmdList, m_EnableGI); // Dispatch the Brixelizer Example Shader. if (m_OutputMode == OutputMode::ExampleShader) DispatchExampleShader(pCmdList); else VisualizeGIDebug(pCmdList); } ++m_FrameIndex; } void BrixelizerGIRenderModule::OnResize(const cauldron::ResolutionInfo& resInfo) { RecreateBrixelizerContext(); m_InitColorHistory = true; } void BrixelizerGIRenderModule::OnNewContentLoaded(ContentBlock* pContentBlock) { MeshComponentMgr* pMeshComponentManager = MeshComponentMgr::Get(); std::lock_guard pipelineLock(m_CriticalSection); for (EntityDataBlock* pEntityData : pContentBlock->EntityDataBlocks) { for (Component* pComponent : pEntityData->Components) { if (pComponent->GetManager() == pMeshComponentManager) { const Mesh* pMesh = reinterpret_cast(pComponent)->GetData().pMesh; const size_t numSurfaces = pMesh->GetNumSurfaces(); for (uint32_t i = 0; i < numSurfaces; ++i) { const Surface* pSurface = pMesh->GetSurface(i); if (pSurface->HasTranslucency()) { continue; } Entity* entity = pComponent->GetOwner(); BrixelizerInstanceInfo instanceInfo = {}; FfxBrixelizerInstanceDescription desc = {}; instanceInfo.entity = entity; instanceInfo.surface = pSurface; instanceInfo.instanceID = FFX_BRIXELIZER_INVALID_ID; instanceInfo.isDynamic = entity->HasComponent(AnimationComponentMgr::Get()); m_Instances.push_back(instanceInfo); } } } } FlushInstances(true); } void BrixelizerGIRenderModule::OnContentUnloaded(ContentBlock* pContentBlock) { MeshComponentMgr* pMeshComponentManager = MeshComponentMgr::Get(); std::lock_guard pipelineLock(m_CriticalSection); std::vector instanceIDs; for (EntityDataBlock* pEntityData : pContentBlock->EntityDataBlocks) { for (Component* pComponent : pEntityData->Components) { if (pComponent->GetManager() == pMeshComponentManager) { const Mesh* pMesh = reinterpret_cast(pComponent)->GetData().pMesh; const size_t numSurfaces = pMesh->GetNumSurfaces(); for (uint32_t i = 0; i < numSurfaces; ++i) { const Surface* pSurface = pMesh->GetSurface(i); if (pSurface->HasTranslucency()) { continue; } Entity* entity = pComponent->GetOwner(); for (uint32_t i = 0; i < m_Instances.size(); ++i) { BrixelizerInstanceInfo* instance = &m_Instances[i]; if (instance->entity == entity) { if (!instance->isDynamic && instance->instanceID != FFX_BRIXELIZER_INVALID_ID) { instanceIDs.push_back(instance->instanceID); } m_Instances[i] = m_Instances[m_Instances.size() - 1]; m_Instances.pop_back(); break; } } } } } } if (instanceIDs.size()) { FfxErrorCode errorCode = ffxBrixelizerDeleteInstances(&m_BrixelizerContext, instanceIDs.data(), (uint32_t)instanceIDs.size()); CauldronAssert(AssertLevel::ASSERT_ERROR, errorCode == FFX_OK, L"Failed call to ffxBrixelizerDeleteInstances."); } } void BrixelizerGIRenderModule::FlushInstances(bool flushStaticInstances) { std::vector instanceDescs; for (uint32_t i = 0; i < m_Instances.size(); ++i) { BrixelizerInstanceInfo* info = &m_Instances[i]; if ((!flushStaticInstances && !info->isDynamic) || (info->instanceID != FFX_BRIXELIZER_INVALID_ID)) { continue; } const Mat4& transform = info->entity->GetTransform(); const Vec4 c = info->surface->Center(); const Vec4 r = info->surface->Radius(); const Vec4 aabbMinVec = c - r; const Vec4 aabbMaxVec = c + r; const Vec4 extents = aabbMaxVec - aabbMinVec; const Vec4 aabbCorners[8] = { aabbMinVec + Vec4(0.0f, 0.0f, 0.0f, 0.0f), aabbMinVec + Vec4(extents.getX(), 0.0f, 0.0f, 0.0f), aabbMinVec + Vec4(0.0f, 0.0f, extents.getZ(), 0.0f), aabbMinVec + Vec4(extents.getX(), 0.0f, extents.getZ(), 0.0f), aabbMinVec + Vec4(0.0f, extents.getY(), 0.0f, 0.0f), aabbMinVec + Vec4(extents.getX(), extents.getY(), 0.0f, 0.0f), aabbMinVec + Vec4(0.0f, extents.getY(), extents.getZ(), 0.0f), aabbMinVec + Vec4(extents.getX(), extents.getY(), extents.getZ(), 0.0f), }; Vec4 minExtents = Vec4(INFINITY, INFINITY, INFINITY, INFINITY); Vec4 maxExtents = Vec4(-INFINITY, -INFINITY, -INFINITY, -INFINITY); for (uint32_t i = 0; i < 8; i++) { minExtents = MinPerElement(minExtents, transform * aabbCorners[i]); maxExtents = MaxPerElement(maxExtents, transform * aabbCorners[i]); } const VertexBufferInformation* vertexBufferInfo = NULL; if (info->isDynamic) { const AnimationComponentData* data = info->entity->GetComponent(AnimationComponentMgr::Get())->GetData(); if (data->m_skinId != -1) { vertexBufferInfo = &data->m_skinnedPositions[info->surface->GetSurfaceID()]; } } if (!vertexBufferInfo) { vertexBufferInfo = &info->surface->GetVertexBuffer(VertexAttributeType::Position); } const IndexBufferInformation& indexBufferInfo = info->surface->GetIndexBuffer(); Buffer* vertexBuffer = vertexBufferInfo->pBuffer; Buffer* indexBuffer = indexBufferInfo.pBuffer; uint32_t vertexBufferIndex = GetBufferIndex(vertexBuffer); uint32_t indexBufferIndex = GetBufferIndex(indexBuffer); FfxBrixelizerInstanceDescription instanceDesc = {}; for (uint32_t i = 0; i < 3; ++i) { instanceDesc.aabb.min[i] = minExtents[i]; instanceDesc.aabb.max[i] = maxExtents[i]; } for (uint32_t row = 0; row < 3; ++row) { for (uint32_t col = 0; col < 4; ++col) { instanceDesc.transform[row*4 + col] = transform.getCol(col)[row]; } } instanceDesc.indexFormat = indexBufferInfo.IndexFormat == ResourceFormat::R16_UINT ? FFX_INDEX_TYPE_UINT16 : FFX_INDEX_TYPE_UINT32; instanceDesc.indexBuffer = indexBufferIndex; instanceDesc.indexBufferOffset = 0; instanceDesc.triangleCount = indexBufferInfo.Count / 3; instanceDesc.vertexBuffer = vertexBufferIndex; CauldronAssert(AssertLevel::ASSERT_ERROR, vertexBufferInfo->AttributeDataFormat == AttributeFormat::Vec3, L"Unexpected vertex buffer format submitted to Brixelizer"); instanceDesc.vertexStride = 3 * sizeof(float); instanceDesc.vertexBufferOffset = 0; instanceDesc.vertexCount = vertexBufferInfo->Count; instanceDesc.vertexFormat = FFX_SURFACE_FORMAT_R32G32B32_FLOAT; instanceDesc.outInstanceID = &info->instanceID; instanceDesc.flags = info->isDynamic ? FFX_BRIXELIZER_INSTANCE_FLAG_DYNAMIC : FFX_BRIXELIZER_INSTANCE_FLAG_NONE; instanceDescs.push_back(instanceDesc); } FfxErrorCode errorCode = ffxBrixelizerCreateInstances(&m_BrixelizerContext, instanceDescs.data(), static_cast(instanceDescs.size())); CauldronAssert(AssertLevel::ASSERT_ERROR, errorCode == FFX_OK, L"Failed call to ffxBrixelizerCreateInstances."); } void BrixelizerGIRenderModule::DeleteInstances() { std::vector instanceIDs; for (BrixelizerInstanceInfo& instance : m_Instances) { if (instance.instanceID != FFX_BRIXELIZER_INVALID_ID) { instanceIDs.push_back(instance.instanceID); instance.instanceID = FFX_BRIXELIZER_INVALID_ID; } } if (instanceIDs.size()) { FfxErrorCode errorCode = ffxBrixelizerDeleteInstances(&m_BrixelizerContext, instanceIDs.data(), (uint32_t)instanceIDs.size()); CauldronAssert(AssertLevel::ASSERT_ERROR, errorCode == FFX_OK, L"Failed call to ffxBrixelizerDeleteInstances."); } } void BrixelizerGIRenderModule::CreateBrixelizerContext() { m_InitializationParameters.sdfCenter[0] = 0.0f; m_InitializationParameters.sdfCenter[1] = 0.0f; m_InitializationParameters.sdfCenter[2] = 0.0f; m_InitializationParameters.flags = FFX_BRIXELIZER_CONTEXT_FLAG_ALL_DEBUG; m_InitializationParameters.numCascades = NUM_BRIXELIZER_CASCADES; float voxelSize = m_MeshUnitSize; for (uint32_t i = 0; i < m_InitializationParameters.numCascades; ++i) { FfxBrixelizerCascadeDescription* cascadeDesc = &m_InitializationParameters.cascadeDescs[i]; cascadeDesc->flags = (FfxBrixelizerCascadeFlag)(FFX_BRIXELIZER_CASCADE_STATIC | FFX_BRIXELIZER_CASCADE_DYNAMIC); cascadeDesc->voxelSize = voxelSize; voxelSize *= m_CascadeSizeRatio; } m_InitializationParameters.backendInterface = m_InitializationParameters.backendInterface; FfxErrorCode errorCode = ffxBrixelizerContextCreate(&m_InitializationParameters, &m_BrixelizerContext); CauldronAssert(AssertLevel::ASSERT_ERROR, errorCode == FFX_OK, L"Failed to create Brixelizer context."); if (errorCode == FFX_OK) { CauldronAssert(ASSERT_CRITICAL, ffxBrixelizerGetEffectVersion() == FFX_SDK_MAKE_VERSION(1, 0, 0), L"FidelityFX Brixelizer GI sample requires linking with a 1.0 version Brixelizer library."); } } void BrixelizerGIRenderModule::DeleteBrixelizerContext() { FfxErrorCode errorCode = ffxBrixelizerContextDestroy(&m_BrixelizerContext); CauldronAssert(AssertLevel::ASSERT_ERROR, errorCode == FFX_OK, L"Failed to delete Brixelizer context."); } void BrixelizerGIRenderModule::RecreateBrixelizerContext() { GetFramework()->GetDevice()->FlushAllCommandQueues(); DeleteInstances(); DeleteBrixelizerGIContext(); DeleteBrixelizerContext(); CreateBrixelizerContext(); CreateBrixelizerGIContext(); m_Buffers.clear(); FlushInstances(true); } void BrixelizerGIRenderModule::UpdateBrixelizerContext(cauldron::CommandList* pCmdList) { GPUScopedProfileCapture updateMarker(pCmdList, L"Brixelizer Update"); // Transition all resources to resource state expected by Brixelizer { std::vector barriers; if (m_pGpuScratchBuffer->GetResource()->GetCurrentResourceState() != ResourceState::UnorderedAccess) barriers.push_back(Barrier::Transition(m_pGpuScratchBuffer->GetResource(), m_pGpuScratchBuffer->GetResource()->GetCurrentResourceState(), ResourceState::UnorderedAccess)); if (m_pColorTarget->GetResource()->GetCurrentResourceState() == ResourceState::UnorderedAccess) barriers.push_back(Barrier::Transition(m_pColorTarget->GetResource(), m_pColorTarget->GetResource()->GetCurrentResourceState(), ResourceState::UnorderedAccess)); barriers.push_back(Barrier::Transition(m_pSdfAtlas->GetResource(), m_pSdfAtlas->GetResource()->GetCurrentResourceState(), ResourceState::UnorderedAccess)); barriers.push_back(Barrier::Transition(m_pBrickAABBs->GetResource(), m_pBrickAABBs->GetResource()->GetCurrentResourceState(), ResourceState::UnorderedAccess)); for (const Buffer* aabbTree : m_pCascadeAABBTrees) barriers.push_back(Barrier::Transition(aabbTree->GetResource(), aabbTree->GetResource()->GetCurrentResourceState(), ResourceState::UnorderedAccess)); for (const Buffer* brickMap : m_pCascadeBrickMaps) barriers.push_back(Barrier::Transition(brickMap->GetResource(), brickMap->GetResource()->GetCurrentResourceState(), ResourceState::UnorderedAccess)); ResourceBarrier(pCmdList, (uint32_t)barriers.size(), barriers.data()); } FfxBrixelizerStats stats = {}; // Fill out the Brixelizer update description. FfxBrixelizerUpdateDescription updateDesc = {}; // Pass in the externally created output resources as FfxResource objects. updateDesc.resources.sdfAtlas = SDKWrapper::ffxGetResource(m_pSdfAtlas->GetResource(), (wchar_t*)m_pSdfAtlas->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_UNORDERED_ACCESS); updateDesc.resources.brickAABBs = SDKWrapper::ffxGetResource(m_pBrickAABBs->GetResource(), (wchar_t*)m_pBrickAABBs->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_UNORDERED_ACCESS); for (uint32_t i = 0; i < FFX_BRIXELIZER_MAX_CASCADES; ++i) { updateDesc.resources.cascadeResources[i].aabbTree = SDKWrapper::ffxGetResource(m_pCascadeAABBTrees[i]->GetResource(), (wchar_t*)m_pCascadeAABBTrees[i]->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_UNORDERED_ACCESS); updateDesc.resources.cascadeResources[i].brickMap = SDKWrapper::ffxGetResource(m_pCascadeBrickMaps[i]->GetResource(), (wchar_t*)m_pCascadeBrickMaps[i]->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_UNORDERED_ACCESS); } updateDesc.frameIndex = m_FrameIndex; updateDesc.debugVisualizationDesc = nullptr; updateDesc.populateDebugAABBsFlags = FFX_BRIXELIZER_POPULATE_AABBS_NONE; updateDesc.maxReferences = 32 * (1 << 20); updateDesc.maxBricksPerBake = 1 << 14; updateDesc.triangleSwapSize = 300 * (1 << 20); updateDesc.outStats = &stats; for (uint32_t i = 0; i < 3; ++i) updateDesc.sdfCenter[i] = m_SdfCenter[i]; FfxBrixelizerDebugVisualizationDescription debugVisDesc = {}; if (m_OutputMode == OutputMode::DebugVisualization) SetupDebugVisualization(updateDesc, debugVisDesc); FfxResource ffxGpuScratchBuffer = SDKWrapper::ffxGetResource(m_pGpuScratchBuffer->GetResource(), L"Scratch Buffer", FFX_RESOURCE_STATE_UNORDERED_ACCESS); ffxGpuScratchBuffer.description.stride = sizeof(uint32_t); size_t scratchBufferSize = 0; updateDesc.outScratchBufferSize = &scratchBufferSize; ffxBrixelizerBakeUpdate(&m_BrixelizerContext, &updateDesc, &m_BrixelizerBakedUpdateDesc); CauldronAssert( AssertLevel::ASSERT_ERROR, scratchBufferSize < GPU_SCRATCH_BUFFER_SIZE, L"Required Brixelizer scratch memory size larger than available GPU buffer."); ffxBrixelizerUpdate(&m_BrixelizerContext, &m_BrixelizerBakedUpdateDesc, ffxGpuScratchBuffer, SDKWrapper::ffxGetCommandList(pCmdList)); // Transition all resources to resource state expected after Brixelizer { std::vector barriers; barriers.push_back(Barrier::Transition(m_pSdfAtlas->GetResource(), m_pSdfAtlas->GetResource()->GetCurrentResourceState(), ResourceState::NonPixelShaderResource)); barriers.push_back(Barrier::Transition(m_pBrickAABBs->GetResource(), m_pBrickAABBs->GetResource()->GetCurrentResourceState(), ResourceState::NonPixelShaderResource)); for (const Buffer* aabbTree : m_pCascadeAABBTrees) barriers.push_back(Barrier::Transition(aabbTree->GetResource(), aabbTree->GetResource()->GetCurrentResourceState(), ResourceState::NonPixelShaderResource)); for (const Buffer* brickMap : m_pCascadeBrickMaps) barriers.push_back(Barrier::Transition(brickMap->GetResource(), brickMap->GetResource()->GetCurrentResourceState(), ResourceState::NonPixelShaderResource)); ResourceBarrier(pCmdList, (uint32_t)barriers.size(), barriers.data()); } // Draw Brixelizer stats { if (m_ResetStats) { m_ResetStats = false; m_MaxStaticTriangles = 0; m_MaxStaticReferences = 0; m_MaxStaticBricks = 0; m_MaxDynamicTriangles = 0; m_MaxDynamicReferences = 0; m_MaxDynamicBricks = 0; } uint64_t freeBricks = stats.contextStats.freeBricks; m_MaxStaticBricks = std::max(m_MaxStaticBricks, (uint64_t)stats.staticCascadeStats.bricksAllocated); m_MaxStaticReferences = std::max(m_MaxStaticReferences, (uint64_t)stats.staticCascadeStats.referencesAllocated); m_MaxStaticTriangles = std::max(m_MaxStaticTriangles, (uint64_t)stats.staticCascadeStats.trianglesAllocated); m_MaxDynamicBricks = std::max(m_MaxDynamicBricks, (uint64_t)stats.dynamicCascadeStats.bricksAllocated); m_MaxDynamicReferences = std::max(m_MaxDynamicReferences, (uint64_t)stats.dynamicCascadeStats.referencesAllocated); m_MaxDynamicTriangles = std::max(m_MaxDynamicTriangles, (uint64_t)stats.dynamicCascadeStats.trianglesAllocated); char buffer[1024] = {}; snprintf(buffer, _countof(buffer), "Free Bricks: %8llu", freeBricks); m_FreeBricksTextElement->SetDesc(buffer); snprintf(buffer, _countof(buffer), "Max Static Bricks: %8llu", m_MaxStaticBricks); m_StaticBricksTextElement->SetDesc(buffer); snprintf(buffer, _countof(buffer), "Max Static Triangles: %8llu", m_MaxStaticTriangles); m_StaticTrianglesTextElement->SetDesc(buffer); snprintf(buffer, _countof(buffer), "Max Static References: %8llu", m_MaxStaticReferences); m_StaticReferencesTextElement->SetDesc(buffer); snprintf(buffer, _countof(buffer), "Max Dynamic Bricks: %8llu", m_MaxDynamicBricks); m_DynamicBricksTextElement->SetDesc(buffer); snprintf(buffer, _countof(buffer), "Max Dynamic Triangles: %8llu", m_MaxDynamicTriangles); m_DynamicTrianglesTextElement->SetDesc(buffer); snprintf(buffer, _countof(buffer), "Max Dynamic References: %8llu", m_MaxDynamicReferences); m_DynamicReferencesTextElement->SetDesc(buffer); } } void BrixelizerGIRenderModule::SetupDebugVisualization(FfxBrixelizerUpdateDescription& updateDesc, FfxBrixelizerDebugVisualizationDescription& debugVisDesc) { ResolutionInfo resInfo = GetFramework()->GetResolutionInfo(); CameraComponent* camera = GetScene()->GetCurrentCamera(); const Mat4& inverseView = camera->GetInverseView(); const Mat4& inverseProjection = camera->GetInverseProjection(); memcpy(&debugVisDesc.inverseViewMatrix, &inverseView, sizeof(debugVisDesc.inverseViewMatrix)); memcpy(&debugVisDesc.inverseProjectionMatrix, &inverseProjection, sizeof(debugVisDesc.inverseProjectionMatrix)); switch (m_DebugVisOutputType) { case DebugVisOutputType::Distance: debugVisDesc.debugState = FFX_BRIXELIZER_TRACE_DEBUG_MODE_DISTANCE; break; case DebugVisOutputType::UVW: debugVisDesc.debugState = FFX_BRIXELIZER_TRACE_DEBUG_MODE_UVW; break; case DebugVisOutputType::Iterations: debugVisDesc.debugState = FFX_BRIXELIZER_TRACE_DEBUG_MODE_ITERATIONS; break; case DebugVisOutputType::Gradient: debugVisDesc.debugState = FFX_BRIXELIZER_TRACE_DEBUG_MODE_GRAD; break; case DebugVisOutputType::BrickID: debugVisDesc.debugState = FFX_BRIXELIZER_TRACE_DEBUG_MODE_BRICK_ID; break; case DebugVisOutputType::CascadeID: debugVisDesc.debugState = FFX_BRIXELIZER_TRACE_DEBUG_MODE_CASCADE_ID; break; default: CauldronAssert(AssertLevel::ASSERT_ERROR, false, L"Unknown debug visualization output type."); break; } uint32_t cascadeIndexOffset = 0; switch (m_CascadeType) { case CascadeType::Static: cascadeIndexOffset = 0; break; case CascadeType::Dynamic: cascadeIndexOffset = NUM_BRIXELIZER_CASCADES; break; case CascadeType::Merged: cascadeIndexOffset = 2 * NUM_BRIXELIZER_CASCADES; break; default: CauldronAssert(AssertLevel::ASSERT_ERROR, false, L"Unknown cascade type."); break; } debugVisDesc.startCascadeIndex = cascadeIndexOffset + m_StartCascadeIdx; debugVisDesc.endCascadeIndex = cascadeIndexOffset + m_EndCascadeIdx; debugVisDesc.tMin = m_TMin; debugVisDesc.tMax = m_TMax; debugVisDesc.sdfSolveEps = m_SdfSolveEps; debugVisDesc.renderWidth = resInfo.RenderWidth; debugVisDesc.renderHeight = resInfo.RenderHeight; debugVisDesc.output = SDKWrapper::ffxGetResource(m_pColorTarget->GetResource(), L"Color Target", FFX_RESOURCE_STATE_UNORDERED_ACCESS); FfxBrixelizerPopulateDebugAABBsFlags populateDebugAABBFlags = FFX_BRIXELIZER_POPULATE_AABBS_NONE; if (m_ShowStaticInstanceAABBs) populateDebugAABBFlags = (FfxBrixelizerPopulateDebugAABBsFlags)(populateDebugAABBFlags | FFX_BRIXELIZER_POPULATE_AABBS_STATIC_INSTANCES); if (m_ShowDynamicInstanceAABBs) populateDebugAABBFlags = (FfxBrixelizerPopulateDebugAABBsFlags)(populateDebugAABBFlags | FFX_BRIXELIZER_POPULATE_AABBS_DYNAMIC_INSTANCES); if (m_ShowCascadeAABBs) populateDebugAABBFlags = (FfxBrixelizerPopulateDebugAABBsFlags)(populateDebugAABBFlags | FFX_BRIXELIZER_POPULATE_AABBS_CASCADE_AABBS); if (m_ShowAABBTreeIndex != -1) debugVisDesc.cascadeDebugAABB[2 * NUM_BRIXELIZER_CASCADES + m_ShowAABBTreeIndex] = FFX_BRIXELIZER_CASCADE_DEBUG_AABB_AABB_TREE; updateDesc.debugVisualizationDesc = &debugVisDesc; updateDesc.populateDebugAABBsFlags = populateDebugAABBFlags; } void BrixelizerGIRenderModule::DispatchExampleShader(cauldron::CommandList* pCmdList) { GPUScopedProfileCapture exampleMarker(pCmdList, L"Brixelizer Example"); const ResourceState currentState = m_pColorTarget->GetResource()->GetCurrentResourceState(); if (currentState != ResourceState::UnorderedAccess) { Barrier barrier = currentState == ResourceState::UnorderedAccess ? Barrier::UAV(m_pColorTarget->GetResource()) : Barrier::Transition(m_pColorTarget->GetResource(), currentState, ResourceState::UnorderedAccess); ResourceBarrier(pCmdList, 1, &barrier); } FfxBrixelizerContextInfo contextInfo = {}; FfxErrorCode error = ffxBrixelizerGetContextInfo(&m_BrixelizerContext, &contextInfo); CauldronAssert(AssertLevel::ASSERT_ERROR, error == FFX_OK, L"Failed to get Brixelizer context info."); BrixelizerExampleConstants constants = {}; constants.SolveEpsilon = m_SdfSolveEps; constants.TMin = m_TMin; constants.TMax = m_TMax; constants.State = (uint32_t)m_ExampleOutputType; CameraComponent* camera = GetScene()->GetCurrentCamera(); const Mat4& inverseView = camera->GetInverseView(); const Mat4& inverseProjection = camera->GetInverseProjection(); memcpy(&constants.InvView, &inverseView, sizeof(constants.InvView)); memcpy(&constants.InvProj, &inverseProjection, sizeof(constants.InvProj)); // Always use the merged cascades for the example shader. uint32_t offset = 2 * NUM_BRIXELIZER_CASCADES; constants.StartCascadeID = m_StartCascadeIdx + offset; constants.EndCascadeID = m_EndCascadeIdx + offset; if (m_ShowBrickOutlines) constants.Flags |= BRIXELIZER_EXAMPLE_SHOW_BRICK_OUTLINES; constants.Alpha = m_Alpha; BufferAddressInfo exampleConstantBuffer = GetDynamicBufferPool()->AllocConstantBuffer(sizeof(constants), &constants); BufferAddressInfo contextConstantBuffer = GetDynamicBufferPool()->AllocConstantBuffer(sizeof(contextInfo), &contextInfo); m_pExampleParameterSet->UpdateRootConstantBuffer(&exampleConstantBuffer, 0); m_pExampleParameterSet->UpdateRootConstantBuffer(&contextConstantBuffer, 1); // Bind the resources needed by Brixelizer. m_pExampleParameterSet->SetBufferSRV(m_pBrickAABBs, 0); m_pExampleParameterSet->SetTextureSRV(m_pSdfAtlas, ViewDimension::Texture3D, 1); for (uint32_t i = 0; i < _countof(m_pCascadeAABBTrees); ++i) m_pExampleParameterSet->SetBufferSRV(m_pCascadeAABBTrees[i], 2 + i); for (uint32_t i = 0; i < _countof(m_pCascadeBrickMaps); ++i) m_pExampleParameterSet->SetBufferSRV(m_pCascadeBrickMaps[i], 26 + i); m_pExampleParameterSet->SetTextureUAV(m_pColorTarget, ViewDimension::Texture2D, 0); m_pExampleParameterSet->Bind(pCmdList, m_pExamplePipeline); SetPipelineState(pCmdList, m_pExamplePipeline); TextureDesc colorTargetDesc = m_pColorTarget->GetDesc(); Dispatch(pCmdList, (colorTargetDesc.Width + 7) / 8, (colorTargetDesc.Height + 7) / 8, 1); // Render modules expect resources coming in/going out to be in a shader read state { Barrier barriers[] = {Barrier::Transition(m_pColorTarget->GetResource(), ResourceState::UnorderedAccess, ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource)}; ResourceBarrier(pCmdList, 1, barriers); } } void BrixelizerGIRenderModule::CreateBrixelizerGIContext() { TextureDesc colorTargetDesc = m_pColorTarget->GetDesc(); FfxBrixelizerGIContextDescription desc = {}; desc.flags = FFX_BRIXELIZER_GI_FLAG_DEPTH_INVERTED; desc.internalResolution = FFX_BRIXELIZER_GI_INTERNAL_RESOLUTION_50_PERCENT; desc.displaySize = {colorTargetDesc.Width, colorTargetDesc.Height}; desc.backendInterface = m_InitializationParameters.backendInterface; FfxErrorCode errorCode = ffxBrixelizerGIContextCreate(&m_BrixelizerGIContext, &desc); CauldronAssert(AssertLevel::ASSERT_ERROR, errorCode == FFX_OK, L"Failed to create Brixelizer GI context."); if (errorCode == FFX_OK) { CauldronAssert(ASSERT_CRITICAL, ffxBrixelizerGIGetEffectVersion() == FFX_SDK_MAKE_VERSION(1, 0, 0), L"FidelityFX Brixelizer GI sample requires linking with a 1.0 version Brixelizer GI library."); } } void BrixelizerGIRenderModule::DeleteBrixelizerGIContext() { FfxErrorCode errorCode = ffxBrixelizerGIContextDestroy(&m_BrixelizerGIContext); CauldronAssert(AssertLevel::ASSERT_ERROR, errorCode == FFX_OK, L"Failed to delete Brixelizer GI context."); } void BrixelizerGIRenderModule::RecreateBrixelizerGIContext() { GetFramework()->GetDevice()->FlushAllCommandQueues(); DeleteBrixelizerGIContext(); CreateBrixelizerGIContext(); } void BrixelizerGIRenderModule::UpdateBrixelizerGIContext(cauldron::CommandList* pCmdList) { CameraComponent* camera = GetScene()->GetCurrentCamera(); const Mat4& view = camera->GetView(); const Mat4& projection = camera->GetProjection(); const Mat4& prevView = camera->GetPreviousView(); { GPUScopedProfileCapture marker(pCmdList, L"Brixelizer GI Update"); const ResourceState diffuseGIState = m_pDiffuseGI->GetResource()->GetCurrentResourceState(); const ResourceState specularGIState = m_pSpecularGI->GetResource()->GetCurrentResourceState(); { Barrier barriers[] = {Barrier::Transition(m_pDiffuseGI->GetResource(), diffuseGIState, ResourceState::NonPixelShaderResource), Barrier::Transition(m_pSpecularGI->GetResource(), specularGIState, ResourceState::NonPixelShaderResource)}; ResourceBarrier(pCmdList, 2, barriers); } m_pEnivornmentMap = GetScene()->GetIBLTexture(IBLTexture::Prefiltered); const SceneLightingInformation& lightingInfo = GetScene()->GetSceneLightInfo(); memcpy(&m_GIDispatchDesc.view, &view, sizeof(m_GIDispatchDesc.view)); memcpy(&m_GIDispatchDesc.projection, &projection, sizeof(m_GIDispatchDesc.projection)); memcpy(&m_GIDispatchDesc.prevView, &prevView, sizeof(m_GIDispatchDesc.prevView)); memcpy(&m_GIDispatchDesc.prevProjection, &m_PrevProjection, sizeof(m_GIDispatchDesc.prevProjection)); m_PrevProjection = projection; memcpy(&m_GIDispatchDesc.cameraPosition, &camera->GetCameraPos(), sizeof(m_GIDispatchDesc.cameraPosition)); m_GIDispatchDesc.startCascade = m_StartCascadeIdx + (2 * NUM_BRIXELIZER_CASCADES); m_GIDispatchDesc.endCascade = m_EndCascadeIdx + (2 * NUM_BRIXELIZER_CASCADES); m_GIDispatchDesc.rayPushoff = m_RayPushoff; m_GIDispatchDesc.sdfSolveEps = m_SdfSolveEps; m_GIDispatchDesc.specularRayPushoff = m_RayPushoff; m_GIDispatchDesc.specularSDFSolveEps = m_SdfSolveEps; m_GIDispatchDesc.tMin = m_TMin; m_GIDispatchDesc.tMax = m_TMax; m_GIDispatchDesc.normalsUnpackMul = 2.0f; m_GIDispatchDesc.normalsUnpackAdd = -1.0f; m_GIDispatchDesc.isRoughnessPerceptual = false; m_GIDispatchDesc.roughnessChannel = 1; m_GIDispatchDesc.roughnessThreshold = 0.9f; m_GIDispatchDesc.environmentMapIntensity = 0.1f; m_GIDispatchDesc.motionVectorScale = { 1.0f, 1.0f}; m_GIDispatchDesc.depth = SDKWrapper::ffxGetResource(m_pDepthBuffer->GetResource(), L"Depth"); m_GIDispatchDesc.normal = SDKWrapper::ffxGetResource(m_pNormalTarget->GetResource(), L"Normal"); m_GIDispatchDesc.roughness = SDKWrapper::ffxGetResource(m_pRoughnessTarget->GetResource(), L"Roughness"); m_GIDispatchDesc.motionVectors = SDKWrapper::ffxGetResource(m_pVelocityBuffer->GetResource(), L"MotionVectors"); m_GIDispatchDesc.historyDepth = SDKWrapper::ffxGetResource(m_pHistoryDepth->GetResource(), L"HistoryDepth"); m_GIDispatchDesc.historyNormal = SDKWrapper::ffxGetResource(m_pHistoryNormals->GetResource(), L"HistoryNormal"); m_GIDispatchDesc.prevLitOutput = SDKWrapper::ffxGetResource(m_pHistoryLitOutput->GetResource(), L"PrevLitOutput"); m_GIDispatchDesc.noiseTexture = SDKWrapper::ffxGetResource(m_NoiseTextures[m_FrameIndex % g_NumNoiseTextures]->GetResource(), L"NoiseTexture"); m_GIDispatchDesc.environmentMap = SDKWrapper::ffxGetResource(m_pEnivornmentMap->GetResource(), L"EnvironmentMap"); m_GIDispatchDesc.sdfAtlas = SDKWrapper::ffxGetResource(m_pSdfAtlas->GetResource(), (wchar_t*)m_pSdfAtlas->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_COMPUTE_READ); m_GIDispatchDesc.bricksAABBs = SDKWrapper::ffxGetResource(m_pBrickAABBs->GetResource(), (wchar_t*)m_pBrickAABBs->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_COMPUTE_READ); for (uint32_t i = 0; i < FFX_BRIXELIZER_MAX_CASCADES; ++i) { m_GIDispatchDesc.cascadeAABBTrees[i] = SDKWrapper::ffxGetResource(m_pCascadeAABBTrees[i]->GetResource(), (wchar_t*)m_pCascadeAABBTrees[i]->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_COMPUTE_READ); m_GIDispatchDesc.cascadeBrickMaps[i] = SDKWrapper::ffxGetResource(m_pCascadeBrickMaps[i]->GetResource(), (wchar_t*)m_pCascadeBrickMaps[i]->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_COMPUTE_READ); } m_GIDispatchDesc.outputDiffuseGI = SDKWrapper::ffxGetResource(m_pDiffuseGI->GetResource(), L"OutputDiffuseGI"); m_GIDispatchDesc.outputSpecularGI = SDKWrapper::ffxGetResource(m_pSpecularGI->GetResource(), L"OutputSpecularGI"); FfxErrorCode error = ffxBrixelizerGetRawContext(&m_BrixelizerContext, &m_GIDispatchDesc.brixelizerContext); CauldronAssert(AssertLevel::ASSERT_ERROR, error == FFX_OK, L"Failed to get Brixelizer context pointer."); ffxBrixelizerGIContextDispatch(&m_BrixelizerGIContext, &m_GIDispatchDesc, SDKWrapper::ffxGetCommandList(pCmdList)); { Barrier barriers[] = {Barrier::Transition(m_pDiffuseGI->GetResource(), ResourceState::NonPixelShaderResource, diffuseGIState), Barrier::Transition(m_pSpecularGI->GetResource(), ResourceState::NonPixelShaderResource, specularGIState)}; ResourceBarrier(pCmdList, 2, barriers); } } if (m_OutputMode == OutputMode::RadianceCache || m_OutputMode == OutputMode::IrradianceCache) { GPUScopedProfileCapture marker(pCmdList, L"Brixelizer GI Debug Visualization"); const ResourceState debugVisState = m_pDiffuseGI->GetResource()->GetCurrentResourceState(); { Barrier barriers[] = {Barrier::Transition(m_pDebugVisualization->GetResource(), debugVisState, ResourceState::UnorderedAccess)}; ResourceBarrier(pCmdList, 1, barriers); } FfxBrixelizerGIDebugDescription debug_desc = {}; memcpy(&debug_desc.view, &view, sizeof(debug_desc.view)); memcpy(&debug_desc.projection, &projection, sizeof(debug_desc.projection)); TextureDesc desc = m_pColorTarget->GetDesc(); debug_desc.outputSize[0] = desc.Width; debug_desc.outputSize[1] = desc.Height; debug_desc.normalsUnpackMul = 2.0f; debug_desc.normalsUnpackAdd = -1.0f; if (m_OutputMode == OutputMode::RadianceCache) debug_desc.debugMode = FFX_BRIXELIZER_GI_DEBUG_MODE_RADIANCE_CACHE; else if (m_OutputMode == OutputMode::IrradianceCache) debug_desc.debugMode = FFX_BRIXELIZER_GI_DEBUG_MODE_IRRADIANCE_CACHE; debug_desc.startCascade = m_StartCascadeIdx + (2 * NUM_BRIXELIZER_CASCADES); debug_desc.endCascade = m_EndCascadeIdx + (2 * NUM_BRIXELIZER_CASCADES); debug_desc.depth = SDKWrapper::ffxGetResource(m_pDepthBuffer->GetResource(), L"Depth"); debug_desc.normal = SDKWrapper::ffxGetResource(m_pNormalTarget->GetResource(), L"Normal"); debug_desc.sdfAtlas = SDKWrapper::ffxGetResource(m_pSdfAtlas->GetResource(), (wchar_t*)m_pSdfAtlas->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_COMPUTE_READ); debug_desc.bricksAABBs = SDKWrapper::ffxGetResource(m_pBrickAABBs->GetResource(), (wchar_t*)m_pBrickAABBs->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_COMPUTE_READ); for (uint32_t i = 0; i < FFX_BRIXELIZER_MAX_CASCADES; ++i) { debug_desc.cascadeAABBTrees[i] = SDKWrapper::ffxGetResource(m_pCascadeAABBTrees[i]->GetResource(), (wchar_t*)m_pCascadeAABBTrees[i]->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_COMPUTE_READ); debug_desc.cascadeBrickMaps[i] = SDKWrapper::ffxGetResource(m_pCascadeBrickMaps[i]->GetResource(), (wchar_t*)m_pCascadeBrickMaps[i]->GetDesc().Name.c_str(), FFX_RESOURCE_STATE_COMPUTE_READ); } debug_desc.outputDebug = SDKWrapper::ffxGetResource(m_pDebugVisualization->GetResource(), L"OutputDebugVisualization", FFX_RESOURCE_STATE_UNORDERED_ACCESS); FfxErrorCode error = ffxBrixelizerGetRawContext(&m_BrixelizerContext, &debug_desc.brixelizerContext); CauldronAssert(AssertLevel::ASSERT_ERROR, error == FFX_OK, L"Failed to get Brixelizer context pointer."); ffxBrixelizerGIContextDebugVisualization(&m_BrixelizerGIContext, &debug_desc, SDKWrapper::ffxGetCommandList(pCmdList)); { Barrier barriers[] = {Barrier::Transition(m_pDebugVisualization->GetResource(), ResourceState::UnorderedAccess, debugVisState)}; ResourceBarrier(pCmdList, 1, barriers); } } } void BrixelizerGIRenderModule::CopyHistoryResource(cauldron::CommandList* pCmdList, const cauldron::Texture* pInput, const cauldron::Texture* pOutput, std::wstring name) { std::wstring markerString = L"Copy History Resource:" + name; GPUScopedProfileCapture marker(pCmdList, markerString.c_str()); TextureCopyDesc desc(pInput->GetResource(), pOutput->GetResource()); CopyTextureRegion(pCmdList, &desc); } void BrixelizerGIRenderModule::CopyHistoryResources(cauldron::CommandList* pCmdList) { const ResourceState historyDepthState = m_pHistoryDepth->GetResource()->GetCurrentResourceState(); const ResourceState historyNormalsState = m_pHistoryNormals->GetResource()->GetCurrentResourceState(); const ResourceState historyLitOutputState = m_pHistoryLitOutput->GetResource()->GetCurrentResourceState(); const ResourceState depthState = m_pDepthBuffer->GetResource()->GetCurrentResourceState(); const ResourceState normalsState = m_pNormalTarget->GetResource()->GetCurrentResourceState(); const ResourceState litOutputState = m_pLitOutputCopy->GetResource()->GetCurrentResourceState(); { Barrier barriers[] = { Barrier::Transition(m_pHistoryDepth->GetResource(), historyDepthState, ResourceState::CopyDest), Barrier::Transition(m_pHistoryNormals->GetResource(), historyNormalsState, ResourceState::CopyDest), Barrier::Transition(m_pHistoryLitOutput->GetResource(), historyLitOutputState, ResourceState::CopyDest), Barrier::Transition(m_pDepthBuffer->GetResource(), depthState, ResourceState::CopySource), Barrier::Transition(m_pNormalTarget->GetResource(), normalsState, ResourceState::CopySource), Barrier::Transition(m_pLitOutputCopy->GetResource(), litOutputState, ResourceState::CopySource), }; ResourceBarrier(pCmdList, _countof(barriers), barriers); } CopyHistoryResource(pCmdList, m_pDepthBuffer, m_pHistoryDepth, L"Depth"); CopyHistoryResource(pCmdList, m_pNormalTarget, m_pHistoryNormals, L"Normals"); CopyHistoryResource(pCmdList, m_pLitOutputCopy, m_pHistoryLitOutput, L"LitOutput"); { Barrier barriers[] = { Barrier::Transition(m_pHistoryDepth->GetResource(), ResourceState::CopyDest, historyDepthState), Barrier::Transition(m_pHistoryNormals->GetResource(), ResourceState::CopyDest, historyNormalsState), Barrier::Transition(m_pHistoryLitOutput->GetResource(), ResourceState::CopyDest, historyLitOutputState), Barrier::Transition(m_pDepthBuffer->GetResource(), ResourceState::CopySource, depthState), Barrier::Transition(m_pNormalTarget->GetResource(), ResourceState::CopySource, normalsState), Barrier::Transition(m_pLitOutputCopy->GetResource(), ResourceState::CopySource, litOutputState), }; ResourceBarrier(pCmdList, _countof(barriers), barriers); } } void BrixelizerGIRenderModule::DeferredLighting(cauldron::CommandList* pCmdList, bool enableGI) { GPUScopedProfileCapture sampleMarker(pCmdList, L"Deferred Lighting"); const ResourceState currentState = m_pColorTarget->GetResource()->GetCurrentResourceState(); const ResourceState copyCurrentState = m_pLitOutputCopy->GetResource()->GetCurrentResourceState(); if (currentState != ResourceState::UnorderedAccess) { Barrier barriers[] = {currentState == ResourceState::UnorderedAccess ? Barrier::UAV(m_pColorTarget->GetResource()) : Barrier::Transition(m_pColorTarget->GetResource(), currentState, ResourceState::UnorderedAccess), Barrier::Transition(m_pLitOutputCopy->GetResource(), copyCurrentState, ResourceState::UnorderedAccess) }; ResourceBarrier(pCmdList, 2, barriers); } if (GetScene()->GetBRDFLutTexture()) { m_pDeferredLightingParameterSet->SetTextureSRV(GetScene()->GetBRDFLutTexture(), ViewDimension::Texture2D, 4); } if (GetScene()->GetScreenSpaceShadowTexture()) { // Store screenSpaceShadowTexture at index 0 in the shadow maps array m_pDeferredLightingParameterSet->SetTextureSRV(GetScene()->GetScreenSpaceShadowTexture(), ViewDimension::Texture2D, 7); } else { ShadowMapResourcePool* pShadowMapResourcePool = GetFramework()->GetShadowMapResourcePool(); for (uint32_t i = 0; i < pShadowMapResourcePool->GetRenderTargetCount(); ++i) { m_pDeferredLightingParameterSet->SetTextureSRV(pShadowMapResourcePool->GetRenderTarget(i), ViewDimension::Texture2D, 7 + i); } } // Update necessary scene frame information BufferAddressInfo sceneBuffers[2]; sceneBuffers[0] = GetDynamicBufferPool()->AllocConstantBuffer(sizeof(SceneInformation), reinterpret_cast(&GetScene()->GetSceneInfo())); sceneBuffers[1] = GetDynamicBufferPool()->AllocConstantBuffer(sizeof(SceneLightingInformation), reinterpret_cast(&GetScene()->GetSceneLightInfo())); m_pDeferredLightingParameterSet->UpdateRootConstantBuffer(&sceneBuffers[0], 0); m_pDeferredLightingParameterSet->UpdateRootConstantBuffer(&sceneBuffers[1], 1); // Allocate a dynamic constant buffers and set GIConstants giConstants = {}; giConstants.DiffuseGIFactor = enableGI ? m_DiffuseGIFactor : 0.0f; giConstants.SpecularGIFactor = enableGI ? m_SpecularGIFactor : 0.0f; giConstants.MultiBounce = m_FrameIndex == 0 ? 0 : static_cast(m_MultiBounce); BufferAddressInfo bufferInfo = GetDynamicBufferPool()->AllocConstantBuffer(sizeof(giConstants), &giConstants); // Update constant buffers m_pDeferredLightingParameterSet->UpdateRootConstantBuffer(&bufferInfo, 2); // Bind everything m_pDeferredLightingParameterSet->Bind(pCmdList, m_pDeferredLightingPipeline); SetPipelineState(pCmdList, m_pDeferredLightingPipeline); // Scale the work accordingly const ResolutionInfo& resInfo = GetFramework()->GetResolutionInfo(); uint32_t dispatchWidth = 0; uint32_t dispatchHeight = 0; if (GetFramework()->GetUpscalingState() == UpscalerState::PreUpscale) { dispatchWidth = resInfo.RenderWidth; dispatchHeight = resInfo.RenderHeight; } else { dispatchWidth = resInfo.DisplayWidth; dispatchHeight = resInfo.DisplayHeight; } const uint32_t numGroupX = DivideRoundingUp(dispatchWidth, 8); const uint32_t numGroupY = DivideRoundingUp(dispatchHeight, 8); Dispatch(pCmdList, numGroupX, numGroupY, 1); // Render modules expect resources coming in/going out to be in a shader read state { Barrier barriers[] = {Barrier::Transition(m_pColorTarget->GetResource(), ResourceState::UnorderedAccess, currentState), Barrier::Transition(m_pLitOutputCopy->GetResource(), ResourceState::UnorderedAccess, copyCurrentState) }; ResourceBarrier(pCmdList, 2, barriers); } } void BrixelizerGIRenderModule::VisualizeGIDebug(cauldron::CommandList* pCmdList) { const cauldron::Texture* currentOutput = nullptr; if (m_OutputMode == OutputMode::DiffuseGI) currentOutput = m_pDiffuseGI; else if (m_OutputMode == OutputMode::SpecularGI) currentOutput = m_pSpecularGI; else if (m_OutputMode == OutputMode::RadianceCache || m_OutputMode == OutputMode::IrradianceCache) currentOutput = m_pDebugVisualization; if (currentOutput) { const ResourceState currentState = currentOutput->GetResource()->GetCurrentResourceState(); if (currentState != ResourceState::NonPixelShaderResource) { Barrier barriers[] = {Barrier::Transition(currentOutput->GetResource(), currentState, ResourceState::NonPixelShaderResource)}; ResourceBarrier(pCmdList, 1, barriers); } m_pPassThroughParameterSet->SetTextureSRV(currentOutput, ViewDimension::Texture2D, 0); m_pPassThroughParameterSet->SetTextureUAV(m_pColorTarget, ViewDimension::Texture2D, 0); m_pPassThroughParameterSet->Bind(pCmdList, m_pPassThroughPipeline); SetPipelineState(pCmdList, m_pPassThroughPipeline); TextureDesc desc = m_pColorTarget->GetDesc(); Dispatch(pCmdList, (desc.Width + 7) / 8, (desc.Height + 7) / 8, 1); if (currentState != ResourceState::NonPixelShaderResource) { Barrier barriers[] = {Barrier::Transition(currentOutput->GetResource(), ResourceState::NonPixelShaderResource, currentState)}; ResourceBarrier(pCmdList, 1, barriers); } } } void BrixelizerGIRenderModule::TextureLoadComplete(const std::vector& textureList, void*) { std::lock_guard noiseTextureLock(m_TextureLoadCallbackMutex); for (auto texture : textureList) m_NoiseTextures.push_back(texture); if (m_NoiseTextures.size() == g_NumNoiseTextures) SetModuleReady(true); } void BrixelizerGIRenderModule::InitUI(cauldron::UISection* uiSection) { m_CommonUIElements.emplace_back(uiSection->RegisterUIElement("Static Settings")); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("Mesh Unit Size", m_MeshUnitSize, 1e-3f, 1.0f)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("Cascade Size Ratio", m_CascadeSizeRatio, 1.1f, 3.0f)); m_StaticUIElements.emplace_back(uiSection->RegisterUIElement("Dynamic Settings")); static std::vector outputModeComboOptions = {"None", "Example Shader", "Debug Visualization", "Diffuse GI", "Specular GI", "Radiance Cache", "Irradiance Cache"}; m_StaticUIElements.emplace_back(uiSection->RegisterUIElement("Output Mode", (int32_t&)m_OutputMode, std::move(outputModeComboOptions))); static std::vector exampleOutputTypeComboOptions = {"Distance", "UVW", "Iterations", "Gradient", "Brick ID"}; m_ExampleUIElements.emplace_back(uiSection->RegisterUIElement("Output Type", (int32_t&)m_ExampleOutputType, std::move(exampleOutputTypeComboOptions))); static std::vector debugOutputTypeComboOptions = {"Distance", "UVW", "Iterations", "Gradient", "Brick ID", "Cascade ID"}; m_DebugUIElements.emplace_back(uiSection->RegisterUIElement("Output Type", (int32_t&)m_DebugVisOutputType, std::move(debugOutputTypeComboOptions))); static std::vector cascadeTypeComboOptions = {"Static", "Dynamic", "Merged"}; m_DebugUIElements.emplace_back(uiSection->RegisterUIElement("Cascade Type", (int32_t&)m_CascadeType, std::move(cascadeTypeComboOptions))); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("Start Cascade", (int32_t&)m_StartCascadeIdx, 0, NUM_BRIXELIZER_CASCADES - 1)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("End Cascade", (int32_t&)m_EndCascadeIdx, 0, NUM_BRIXELIZER_CASCADES - 1)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("SDF Solve Epsilon", m_SdfSolveEps, 1e-6f, 1.0f)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement("SDF Center Follow Camera", m_SdfCenterFollowCamera)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("TMin", m_TMin, 0.0f, 10.0f)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("TMax", m_TMax, 0.0f, 10000.0f)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("Ray Pushoff", m_RayPushoff, 0.0f, 10.0f)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("Diffuse GI Factor", m_DiffuseGIFactor, 0.0f, 10.0f)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement>("Specular GI Factor", m_SpecularGIFactor, 0.0f, 10.0f)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement("Enable GI", m_EnableGI)); m_CommonUIElements.emplace_back(uiSection->RegisterUIElement("Multi-Bounce", m_MultiBounce)); m_DebugUIElements.emplace_back(uiSection->RegisterUIElement("Show Static Instance AABBs", m_ShowStaticInstanceAABBs)); m_DebugUIElements.emplace_back(uiSection->RegisterUIElement("Show Dynamic Instance AABBs", m_ShowDynamicInstanceAABBs)); m_DebugUIElements.emplace_back(uiSection->RegisterUIElement("Show Cascade AABBs", m_ShowCascadeAABBs)); m_DebugUIElements.emplace_back(uiSection->RegisterUIElement>("Show AABB Tree Index", m_ShowAABBTreeIndex, -1, NUM_BRIXELIZER_CASCADES - 1)); m_ExampleUIElements.emplace_back(uiSection->RegisterUIElement("Show Brick Outlines", m_ShowBrickOutlines)); m_ExampleUIElements.emplace_back(uiSection->RegisterUIElement>("Alpha", m_Alpha, 0.0f, 1.0f)); m_StaticUIElements.emplace_back(uiSection->RegisterUIElement("Performance")); m_StaticUIElements.emplace_back(uiSection->RegisterUIElement("Reset Stats", m_ResetStats)); m_FreeBricksTextElement = uiSection->RegisterUIElement(""); m_StaticBricksTextElement = uiSection->RegisterUIElement(""); m_StaticTrianglesTextElement = uiSection->RegisterUIElement(""); m_StaticReferencesTextElement = uiSection->RegisterUIElement(""); m_DynamicBricksTextElement = uiSection->RegisterUIElement(""); m_DynamicTrianglesTextElement = uiSection->RegisterUIElement(""); m_DynamicReferencesTextElement = uiSection->RegisterUIElement(""); m_StaticUIElements.emplace_back(m_FreeBricksTextElement); m_StaticUIElements.emplace_back(m_StaticBricksTextElement); m_StaticUIElements.emplace_back(m_StaticTrianglesTextElement); m_StaticUIElements.emplace_back(m_StaticReferencesTextElement); m_StaticUIElements.emplace_back(m_DynamicBricksTextElement); m_StaticUIElements.emplace_back(m_DynamicTrianglesTextElement); m_StaticUIElements.emplace_back(m_DynamicReferencesTextElement); UpdateUIElementVisibility(); } void BrixelizerGIRenderModule::UpdateUIElementVisibility() { bool enabled = ModuleEnabled(); if (!enabled) { for (auto uiElement : m_StaticUIElements) uiElement->Show(false); for (auto uiElement : m_CommonUIElements) uiElement->Show(false); for (auto uiElement : m_DebugUIElements) uiElement->Show(false); for (auto uiElement : m_ExampleUIElements) uiElement->Show(false); return; } for (auto uiElement : m_StaticUIElements) uiElement->Show(true); for (auto uiElement : m_CommonUIElements) uiElement->Show(true); for (auto uiElement : m_DebugUIElements) uiElement->Show(m_OutputMode == OutputMode::DebugVisualization); for (auto uiElement : m_ExampleUIElements) uiElement->Show(m_OutputMode == OutputMode::ExampleShader); } void BrixelizerGIRenderModule::UpdateConfig() { // Make sure the values set from the UI are valid. m_EndCascadeIdx = std::max(m_EndCascadeIdx, m_StartCascadeIdx); m_StartCascadeIdx = std::min(m_StartCascadeIdx, m_EndCascadeIdx); m_TMax = std::max(m_TMin, m_TMax); m_TMin = std::min(m_TMin, m_TMax); if (m_SdfCenterFollowCamera) { // Update the Brixelizer SDF center position to follow the camera. Vec3 cameraPos = GetScene()->GetCurrentCamera()->GetCameraPos(); m_SdfCenter[0] = cameraPos.getX(); m_SdfCenter[1] = cameraPos.getY(); m_SdfCenter[2] = cameraPos.getZ(); } } uint32_t BrixelizerGIRenderModule::GetBufferIndex(const cauldron::Buffer* buffer) { for (BrixelizerBufferInfo& bufferInfo : m_Buffers) { if (bufferInfo.buffer == buffer) return bufferInfo.index; } BufferDesc bufferDesc = buffer->GetDesc(); const GPUResource* resource = buffer->GetResource(); wchar_t name[256] = {}; _snwprintf_s(name, _countof(name), L"Vertex Buffer (\"%s\")", bufferDesc.Name.c_str()); FfxResource ffxResource = SDKWrapper::ffxGetResource(resource, name, FFX_RESOURCE_STATE_PIXEL_COMPUTE_READ); uint32_t bufferIndex = 0; FfxBrixelizerBufferDescription brixelizerBufferDesc = {}; brixelizerBufferDesc.buffer = ffxResource; brixelizerBufferDesc.outIndex = &bufferIndex; ffxBrixelizerRegisterBuffers(&m_BrixelizerContext, &brixelizerBufferDesc, 1); BrixelizerBufferInfo info; info.index = bufferIndex; info.buffer = buffer; m_Buffers.push_back(info); return info.index; }