From efa43e2bd2475a4dec6771bf9759f6a99f7d77ed Mon Sep 17 00:00:00 2001 From: azhirnov Date: Tue, 3 Nov 2020 13:52:24 +0300 Subject: fixed resource state transitions, some improvements for ray tracing --- Common/interface/StringPool.hpp | 4 + .../GraphicsEngine/include/BottomLevelASBase.hpp | 16 + .../GraphicsEngine/include/DeviceContextBase.hpp | 98 ++- Graphics/GraphicsEngine/include/ShaderBase.hpp | 3 + .../include/ShaderBindingTableBase.hpp | 169 +++-- Graphics/GraphicsEngine/include/TopLevelASBase.hpp | 81 ++- Graphics/GraphicsEngine/interface/DeviceContext.h | 37 +- Graphics/GraphicsEngine/interface/PipelineState.h | 11 +- .../GraphicsEngine/interface/ShaderBindingTable.h | 5 +- .../include/DeviceContextD3D11Impl.hpp | 2 +- .../include/PipelineStateD3D12Impl.hpp | 7 +- .../include/RenderDeviceD3D12Impl.hpp | 6 +- .../include/ShaderBindingTableD3D12Impl.hpp | 7 - .../include/TopLevelASD3D12Impl.hpp | 5 +- .../interface/ShaderBindingTableD3D12.h | 1 + .../src/DeviceContextD3D12Impl.cpp | 44 +- .../src/PipelineStateD3D12Impl.cpp | 45 +- Graphics/GraphicsEngineD3D12/src/RootSignature.cpp | 2 +- .../src/ShaderBindingTableD3D12Impl.cpp | 40 -- .../include/DeviceContextGLImpl.hpp | 2 +- .../include/RenderDeviceVkImpl.hpp | 4 + .../include/ShaderBindingTableVkImpl.hpp | 7 - .../include/TopLevelASVkImpl.hpp | 5 +- .../src/DeviceContextVkImpl.cpp | 111 +-- .../src/PipelineStateVkImpl.cpp | 11 +- .../src/ShaderBindingTableVkImpl.cpp | 45 -- .../src/ShaderResourceCacheVk.cpp | 40 +- .../src/VulkanTypeConversions.cpp | 29 +- .../include/InlineShaders/RayTracingTestGLSL.h | 120 +++- .../include/InlineShaders/RayTracingTestHLSL.h | 99 ++- .../include/RayTracingTestConstants.hpp | 155 +++++ .../src/D3D12/RayTracingReferenceD3D12.cpp | 679 ++++++++++++++++--- Tests/DiligentCoreAPITest/src/RayTracingTest.cpp | 333 +++++++-- .../src/Vulkan/RayTracingReferenceVk.cpp | 746 +++++++++++++++------ 34 files changed, 2312 insertions(+), 657 deletions(-) create mode 100644 Tests/DiligentCoreAPITest/include/RayTracingTestConstants.hpp diff --git a/Common/interface/StringPool.hpp b/Common/interface/StringPool.hpp index 793668bf..b44711fe 100644 --- a/Common/interface/StringPool.hpp +++ b/Common/interface/StringPool.hpp @@ -161,6 +161,10 @@ public: VERIFY(m_pCurrPtr <= m_pBuffer + m_ReservedSize, "Buffer overflow"); return m_pCurrPtr - m_pBuffer; } + size_t GetReservedSize() const + { + return m_ReservedSize; + } private: Char* m_pBuffer = nullptr; diff --git a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp index 41f2fdf3..2bdd51dc 100644 --- a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp +++ b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp @@ -184,6 +184,18 @@ public: return (this->m_State & State) == State; } +#ifdef DILIGENT_DEVELOPMENT + void UpdateVersion() + { + m_Version.fetch_add(1); + } + + Uint32 GetVersion() const + { + return m_Version.load(); + } +#endif + protected: static void ValidateBottomLevelASDesc(const BottomLevelASDesc& Desc) { @@ -215,6 +227,10 @@ protected: std::unordered_map m_NameToIndex; StringPool m_StringPool; + +#ifdef DILIGENT_DEVELOPMENT + std::atomic m_Version{0}; +#endif }; } // namespace Diligent diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 829416d2..ba586f4b 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -1855,13 +1855,23 @@ void DeviceContextBase:: DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of buffer '", BuffDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); DEV_CHECK_ERR(VerifyResourceStates(OldState, false), "Invlaid old state specified for buffer '", BuffDesc.Name, "'"); } - else if (RefCntAutoPtr pBLAS{Barrier.pResource, IID_BottomLevelAS}) + else if (RefCntAutoPtr pBottomLevelAS{Barrier.pResource, IID_BottomLevelAS}) { - // AZ TODO + const auto& BLASDesc = pBottomLevelAS->GetDesc(); + OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pBottomLevelAS->GetState(); + DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of BLAS '", BLASDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); + DEV_CHECK_ERR(Barrier.NewState == RESOURCE_STATE_BUILD_AS_READ || Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE || Barrier.NewState == RESOURCE_STATE_RAY_TRACING, + "Invlaid new state specified for BLAS '", BLASDesc.Name, "'"); + DEV_CHECK_ERR(Barrier.TransitionType != STATE_TRANSITION_TYPE_IMMEDIATE, "Split barriers are not supported for BLAS"); } - else if (RefCntAutoPtr pTLAS{Barrier.pResource, IID_TopLevelAS}) + else if (RefCntAutoPtr pTopLevelAS{Barrier.pResource, IID_TopLevelAS}) { - // AZ TODO + const auto& TLASDesc = pTopLevelAS->GetDesc(); + OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pTopLevelAS->GetState(); + DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of TLAS '", TLASDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); + DEV_CHECK_ERR(Barrier.NewState == RESOURCE_STATE_BUILD_AS_READ || Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE || Barrier.NewState == RESOURCE_STATE_RAY_TRACING, + "Invlaid new state specified for TLAS '", TLASDesc.Name, "'"); + DEV_CHECK_ERR(Barrier.TransitionType != STATE_TRANSITION_TYPE_IMMEDIATE, "Split barriers are not supported for TLAS"); } else { @@ -1943,6 +1953,12 @@ bool DeviceContextBase:: template bool DeviceContextBase::BuildBLAS(const BLASBuildAttribs& Attribs, int) { + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("BuildBLAS command must be performed outside of render pass"); + return false; + } + if (Attribs.pBLAS == nullptr) { LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBLAS must not be null"); @@ -2090,6 +2106,7 @@ bool DeviceContextBase::BuildBLAS(const BLA return false; } } +#endif // DILIGENT_DEVELOPMENT const auto& BLASDesc = Attribs.pBLAS->GetDesc(); @@ -2113,7 +2130,7 @@ bool DeviceContextBase::BuildBLAS(const BLA return false; } - if (ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset > Attribs.pBLAS->GetScratchBufferSizes().Build) + if (ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset < Attribs.pBLAS->GetScratchBufferSizes().Build) { LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pScratchBuffer size is too small, use pBLAS->GetScratchBufferSizes().Build to get required size for scratch buffer"); return false; @@ -2124,7 +2141,6 @@ bool DeviceContextBase::BuildBLAS(const BLA LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must be created with BIND_RAY_TRACING flag"); return false; } -#endif // DILIGENT_DEVELOPMENT return true; } @@ -2132,6 +2148,12 @@ bool DeviceContextBase::BuildBLAS(const BLA template bool DeviceContextBase::BuildTLAS(const TLASBuildAttribs& Attribs, int) { + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("BuildTLAS command must be performed outside of render pass"); + return false; + } + if (Attribs.pTLAS == nullptr) { LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pTLAS must not be null"); @@ -2162,7 +2184,6 @@ bool DeviceContextBase::BuildTLAS(const TLA return false; } -#ifdef DILIGENT_DEVELOPMENT const auto& TLASDesc = Attribs.pTLAS->GetDesc(); if (Attribs.InstanceCount > TLASDesc.MaxInstanceCount) @@ -2171,9 +2192,11 @@ bool DeviceContextBase::BuildTLAS(const TLA return false; } - const auto& InstDesc = Attribs.pInstanceBuffer->GetDesc(); - const size_t InstDataSize = Attribs.InstanceCount * TLAS_INSTANCE_DATA_SIZE; - Uint32 AutoOffsetCounter = 0; + const auto& InstDesc = Attribs.pInstanceBuffer->GetDesc(); + const size_t InstDataSize = Attribs.InstanceCount * TLAS_INSTANCE_DATA_SIZE; + +#ifdef DILIGENT_DEVELOPMENT + Uint32 AutoOffsetCounter = 0; // calculate instance data size for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) @@ -2203,6 +2226,7 @@ bool DeviceContextBase::BuildTLAS(const TLA LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: exactly all pInstances[i].ContributionToHitGroupIndex must be TLAS_INSTANCE_OFFSET_AUTO or not"); return false; } +#endif // DILIGENT_DEVELOPMENT if (Attribs.InstanceBufferOffset > InstDesc.uiSizeInBytes) { @@ -2210,15 +2234,15 @@ bool DeviceContextBase::BuildTLAS(const TLA return false; } - if (InstDesc.uiSizeInBytes - Attribs.InstanceBufferOffset > InstDataSize) + if (InstDesc.uiSizeInBytes - Attribs.InstanceBufferOffset < InstDataSize) { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceaBuffer size is too small, ..."); + LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceBuffer size is too small, ..."); return false; } if ((InstDesc.BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING) { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceaBuffer must be created with BIND_RAY_TRACING flag"); + LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceBuffer must be created with BIND_RAY_TRACING flag"); return false; } @@ -2230,7 +2254,7 @@ bool DeviceContextBase::BuildTLAS(const TLA return false; } - if (ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset > Attribs.pTLAS->GetScratchBufferSizes().Build) + if (ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset < Attribs.pTLAS->GetScratchBufferSizes().Build) { LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer size is too small, use pTLAS->GetScratchBufferSizes().Build to get required size for scratch buffer"); return false; @@ -2241,7 +2265,6 @@ bool DeviceContextBase::BuildTLAS(const TLA LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must be created with BIND_RAY_TRACING flag"); return false; } -#endif // DILIGENT_DEVELOPMENT return true; } @@ -2261,6 +2284,12 @@ bool DeviceContextBase::CopyBLAS(const Copy return false; } + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("CopyBLAS command must be performed outside of render pass"); + return false; + } + #ifdef DILIGENT_DEVELOPMENT if (Attribs.Mode == COPY_AS_MODE_CLONE) { @@ -2338,7 +2367,19 @@ bool DeviceContextBase::CopyTLAS(const Copy return false; } + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("CopyTLAS command must be performed outside of render pass"); + return false; + } + #ifdef DILIGENT_DEVELOPMENT + if (!ValidatedCast(Attribs.pSrc)->CheckBLASVersion()) + { + LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pSrc must be rebuilded to apply BLAS changes before being copied to another TLAS"); + return false; + } + if (Attribs.Mode == COPY_AS_MODE_CLONE) { auto& SrcDesc = Attribs.pSrc->GetDesc(); @@ -2370,6 +2411,33 @@ bool DeviceContextBase::TraceRays(const Tra return false; } +#ifdef DILIGENT_DEVELOPMENT + if (!Attribs.pSBT->Verify()) + { + LOG_ERROR_MESSAGE("IDeviceContext::TraceRays: pSBT content is not valid"); + return false; + } +#endif // DILIGENT_DEVELOPMENT + + if (!m_pPipelineState) + { + LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: no pipeline state is bound."); + return false; + } + + if (!m_pPipelineState->GetDesc().IsRayTracingPipeline()) + { + LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a ray tracing pipeline."); + return false; + } + + if (Attribs.pSBT->GetDesc().pPSO != m_pPipelineState) + { + LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: currently bound pipeline ", m_pPipelineState->GetDesc().Name, + "doesn't match the pipeline ", Attribs.pSBT->GetDesc().pPSO->GetDesc().Name, " that was used in ShaderBindingTable"); + return false; + } + if (Attribs.DimensionX == 0) LOG_WARNING_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: DimensionX is zero."); diff --git a/Graphics/GraphicsEngine/include/ShaderBase.hpp b/Graphics/GraphicsEngine/include/ShaderBase.hpp index 24ad92ee..8b6e9efa 100644 --- a/Graphics/GraphicsEngine/include/ShaderBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderBase.hpp @@ -79,6 +79,9 @@ public: if ((ShdrDesc.ShaderType == SHADER_TYPE_AMPLIFICATION || ShdrDesc.ShaderType == SHADER_TYPE_MESH) && !deviceFeatures.MeshShaders) LOG_ERROR_AND_THROW("Mesh shaders are not supported by this device"); + + if ((ShdrDesc.ShaderType >= SHADER_TYPE_RAY_GEN && ShdrDesc.ShaderType <= SHADER_TYPE_CALLABLE) && !deviceFeatures.RayTracing) + LOG_ERROR_AND_THROW("Ray tracing shaders are not supported by this device"); } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_Shader, TDeviceObjectBase) diff --git a/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp index 35371958..b5642a75 100644 --- a/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp @@ -65,41 +65,78 @@ public: TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal} { ValidateShaderBindingTableDesc(Desc); + + this->m_pPSO = ValidatedCast(this->m_Desc.pPSO); + this->m_ShaderRecordSize = this->m_pPSO->GetRayTracingPipelineDesc().ShaderRecordSize; + this->m_ShaderRecordStride = this->m_ShaderRecordSize + this->m_pDevice->GetShaderGroupHandleSize(); } ~ShaderBindingTableBase() { } - void BindRayGenShader(const char* ShaderGroupName, const void* Data, Uint32 DataSize) override final + void DILIGENT_CALL_TYPE Reset(const ShaderBindingTableDesc& Desc) override final { - VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + this->m_RayGenShaderRecord.clear(); + this->m_MissShadersRecord.clear(); + this->m_CallableShadersRecord.clear(); + this->m_HitGroupsRecord.clear(); + this->m_Changed = true; + this->m_pPSO = nullptr; + this->m_Desc = {}; + + try + { + ValidateShaderBindingTableDesc(Desc); + } + catch (const std::runtime_error&) + { + return; + } - this->m_RayGenShaderRecord.resize(this->m_ShaderRecordStride); - ValidatedCast(this->m_Desc.pPSO)->CopyShaderHandle(ShaderGroupName, this->m_RayGenShaderRecord.data(), this->m_ShaderRecordStride); + this->m_Desc = Desc; + this->m_pPSO = ValidatedCast(this->m_Desc.pPSO); + this->m_ShaderRecordSize = this->m_pPSO->GetRayTracingPipelineDesc().ShaderRecordSize; + this->m_ShaderRecordStride = this->m_ShaderRecordSize + this->m_pDevice->GetShaderGroupHandleSize(); + } + + void DILIGENT_CALL_TYPE BindRayGenShader(const char* ShaderGroupName, const void* Data, Uint32 DataSize) override final + { + VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); + VERIFY_EXPR(Data == nullptr || (DataSize == this->m_ShaderRecordSize)); + + this->m_RayGenShaderRecord.resize(this->m_ShaderRecordStride, EmptyElem); + this->m_pPSO->CopyShaderHandle(ShaderGroupName, this->m_RayGenShaderRecord.data(), this->m_ShaderRecordStride); + + const Uint32 GroupSize = this->m_pDevice->GetShaderGroupHandleSize(); + std::memcpy(this->m_RayGenShaderRecord.data() + GroupSize, Data, DataSize); this->m_Changed = true; } - void BindMissShader(const char* ShaderGroupName, Uint32 MissIndex, const void* Data, Uint32 DataSize) override final + void DILIGENT_CALL_TYPE BindMissShader(const char* ShaderGroupName, Uint32 MissIndex, const void* Data, Uint32 DataSize) override final { - VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); + VERIFY_EXPR(Data == nullptr || (DataSize == this->m_ShaderRecordSize)); - const Uint32 Offset = MissIndex * this->m_ShaderRecordStride; - this->m_MissShadersRecord.resize(std::max(this->m_MissShadersRecord.size(), Offset + this->m_ShaderRecordStride)); + const Uint32 GroupSize = this->m_pDevice->GetShaderGroupHandleSize(); + const Uint32 Offset = MissIndex * this->m_ShaderRecordStride; + this->m_MissShadersRecord.resize(std::max(this->m_MissShadersRecord.size(), Offset + this->m_ShaderRecordStride), EmptyElem); - ValidatedCast(this->m_Desc.pPSO)->CopyShaderHandle(ShaderGroupName, this->m_MissShadersRecord.data() + Offset, this->m_ShaderRecordStride); + this->m_pPSO->CopyShaderHandle(ShaderGroupName, this->m_MissShadersRecord.data() + Offset, this->m_ShaderRecordStride); + std::memcpy(this->m_MissShadersRecord.data() + Offset + GroupSize, Data, DataSize); this->m_Changed = true; } - void BindHitGroup(ITopLevelAS* pTLAS, - const char* InstanceName, - const char* GeometryName, - Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data, - Uint32 DataSize) override final + void DILIGENT_CALL_TYPE BindHitGroup(ITopLevelAS* pTLAS, + const char* InstanceName, + const char* GeometryName, + Uint32 RayOffsetInHitGroupIndex, + const char* ShaderGroupName, + const void* Data, + Uint32 DataSize) override final { - VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); + VERIFY_EXPR(Data == nullptr || (DataSize == this->m_ShaderRecordSize)); VERIFY_EXPR(pTLAS != nullptr); VERIFY_EXPR(RayOffsetInHitGroupIndex < this->m_Desc.HitShadersPerInstance); VERIFY_EXPR(pTLAS->GetDesc().BindingMode == SHADER_BINDING_MODE_PER_GEOMETRY); @@ -111,21 +148,23 @@ public: const Uint32 GeometryIndex = Desc.pBLAS->GetGeometryIndex(GeometryName); const Uint32 Index = InstanceIndex + GeometryIndex * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; const Uint32 Offset = Index * this->m_ShaderRecordStride; + const Uint32 GroupSize = this->m_pDevice->GetShaderGroupHandleSize(); - this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), Offset + this->m_ShaderRecordStride)); + this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), Offset + this->m_ShaderRecordStride), EmptyElem); - ValidatedCast(this->m_Desc.pPSO)->CopyShaderHandle(ShaderGroupName, this->m_HitGroupsRecord.data() + Offset, this->m_ShaderRecordStride); + this->m_pPSO->CopyShaderHandle(ShaderGroupName, this->m_HitGroupsRecord.data() + Offset, this->m_ShaderRecordStride); + std::memcpy(this->m_HitGroupsRecord.data() + Offset + GroupSize, Data, DataSize); this->m_Changed = true; } - void BindHitGroups(ITopLevelAS* pTLAS, - const char* InstanceName, - Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data, - Uint32 DataSize) override final + void DILIGENT_CALL_TYPE BindHitGroups(ITopLevelAS* pTLAS, + const char* InstanceName, + Uint32 RayOffsetInHitGroupIndex, + const char* ShaderGroupName, + const void* Data, + Uint32 DataSize) override final { - VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); VERIFY_EXPR(pTLAS != nullptr); VERIFY_EXPR(RayOffsetInHitGroupIndex < this->m_Desc.HitShadersPerInstance); VERIFY_EXPR(pTLAS->GetDesc().BindingMode == SHADER_BINDING_MODE_PER_GEOMETRY || @@ -134,39 +173,64 @@ public: const auto Desc = pTLAS->GetInstanceDesc(InstanceName); VERIFY_EXPR(Desc.pBLAS != nullptr); - const Uint32 InstanceIndex = Desc.ContributionToHitGroupIndex; - const auto& GeometryDesc = Desc.pBLAS->GetDesc(); - const Uint32 GeometryCount = GeometryDesc.BoxCount + GeometryDesc.TriangleCount; - const Uint32 BeginIndex = InstanceIndex + 0 * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; - const Uint32 EndIndex = InstanceIndex + GeometryCount * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; - PipelineStateImplType* pPSO = ValidatedCast(this->m_Desc.pPSO); + const Uint32 InstanceIndex = Desc.ContributionToHitGroupIndex; + const auto& GeometryDesc = Desc.pBLAS->GetDesc(); + Uint32 GeometryCount = 0; + + switch (pTLAS->GetDesc().BindingMode) + { + // clang-format off + case SHADER_BINDING_MODE_PER_GEOMETRY: GeometryCount = GeometryDesc.BoxCount + GeometryDesc.TriangleCount; break; + case SHADER_BINDING_MODE_PER_INSTANCE: GeometryCount = 1; break; + default: UNEXPECTED("unknown binding mode"); + // clang-format on + } + + VERIFY_EXPR(Data == nullptr || (DataSize == this->m_ShaderRecordSize * GeometryCount)); - this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), EndIndex * this->m_ShaderRecordStride)); + const Uint32 BeginIndex = InstanceIndex + 0 * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; + const Uint32 EndIndex = InstanceIndex + GeometryCount * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; + const Uint32 GroupSize = this->m_pDevice->GetShaderGroupHandleSize(); + const auto* DataPtr = static_cast(Data); + + this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), EndIndex * this->m_ShaderRecordStride), EmptyElem); for (Uint32 i = 0; i < GeometryCount; ++i) { Uint32 Offset = (BeginIndex + i) * this->m_ShaderRecordStride; - pPSO->CopyShaderHandle(ShaderGroupName, this->m_HitGroupsRecord.data() + Offset, this->m_ShaderRecordStride); + this->m_pPSO->CopyShaderHandle(ShaderGroupName, this->m_HitGroupsRecord.data() + Offset, this->m_ShaderRecordStride); + + std::memcpy(this->m_HitGroupsRecord.data() + Offset + GroupSize, DataPtr, this->m_ShaderRecordSize); + DataPtr += this->m_ShaderRecordSize; } this->m_Changed = true; } - void BindCallableShader(const char* ShaderGroupName, - Uint32 CallableIndex, - const void* Data, - Uint32 DataSize) override final + void DILIGENT_CALL_TYPE BindCallableShader(const char* ShaderGroupName, + Uint32 CallableIndex, + const void* Data, + Uint32 DataSize) override final { - VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); + VERIFY_EXPR(Data == nullptr || (DataSize == this->m_ShaderRecordSize)); - const Uint32 Offset = CallableIndex * this->m_ShaderRecordStride; - this->m_CallableShadersRecord.resize(std::max(this->m_CallableShadersRecord.size(), Offset + this->m_ShaderRecordStride)); + const Uint32 GroupSize = this->m_pDevice->GetShaderGroupHandleSize(); + const Uint32 Offset = CallableIndex * this->m_ShaderRecordStride; + this->m_CallableShadersRecord.resize(std::max(this->m_CallableShadersRecord.size(), Offset + this->m_ShaderRecordStride), EmptyElem); - ValidatedCast(this->m_Desc.pPSO)->CopyShaderHandle(ShaderGroupName, this->m_CallableShadersRecord.data() + Offset, this->m_ShaderRecordStride); + this->m_pPSO->CopyShaderHandle(ShaderGroupName, this->m_CallableShadersRecord.data() + Offset, this->m_ShaderRecordStride); + std::memcpy(this->m_CallableShadersRecord.data() + Offset + GroupSize, Data, DataSize); this->m_Changed = true; } + Bool DILIGENT_CALL_TYPE Verify() const override final + { + // AZ TODO + return true; + } + protected: - static void ValidateShaderBindingTableDesc(const ShaderBindingTableDesc& Desc) + void ValidateShaderBindingTableDesc(const ShaderBindingTableDesc& Desc) const { #define LOG_SBT_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of Shader binding table '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__) @@ -180,6 +244,20 @@ protected: LOG_SBT_ERROR_AND_THROW("pPSO must be ray tracing pipeline"); } + const auto ShaderGroupHandleSize = this->m_pDevice->GetShaderGroupHandleSize(); + const auto MaxShaderRecordStride = this->m_pDevice->GetMaxShaderRecordStride(); + const auto ShaderRecordSize = Desc.pPSO->GetRayTracingPipelineDesc().ShaderRecordSize; + const auto ShaderRecordStride = ShaderRecordSize + ShaderGroupHandleSize; + + if (ShaderRecordStride > MaxShaderRecordStride) + { + LOG_SBT_ERROR_AND_THROW("ShaderRecordSize(", ShaderRecordSize, ") is too big, max size is: ", MaxShaderRecordStride - ShaderGroupHandleSize); + } + + if (ShaderRecordStride % ShaderGroupHandleSize != 0) + { + LOG_SBT_ERROR_AND_THROW("ShaderRecordSize(", ShaderRecordSize, ") plus ShaderGroupHandleSize(", ShaderGroupHandleSize, ") must be multiple of ", ShaderGroupHandleSize); + } #undef LOG_SBT_ERROR_AND_THROW } @@ -191,8 +269,13 @@ protected: std::vector m_CallableShadersRecord; std::vector m_HitGroupsRecord; + RefCntAutoPtr m_pPSO; + + Uint32 m_ShaderRecordSize = 0; Uint32 m_ShaderRecordStride = 0; bool m_Changed = true; + + static const Uint8 EmptyElem = 0xA7; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngine/include/TopLevelASBase.hpp b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp index ab56636f..b03d9e5c 100644 --- a/Graphics/GraphicsEngine/include/TopLevelASBase.hpp +++ b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp @@ -47,7 +47,7 @@ namespace Diligent /// (Diligent::ITopLevelASD3D12 or Diligent::ITopLevelASVk). /// \tparam RenderDeviceImplType - type of the render device implementation /// (Diligent::RenderDeviceD3D12Impl or Diligent::RenderDeviceVkImpl) -template +template class TopLevelASBase : public DeviceObjectBase { public: @@ -73,8 +73,9 @@ public: void SetInstanceData(const TLASBuildInstanceData* pInstances, Uint32 InstanceCount, Uint32 HitShadersPerInstance) { - m_Instances.clear(); - m_StringPool.Release(); + this->m_Instances.clear(); + this->m_StringPool.Release(); + this->m_HitShadersPerInstance = HitShadersPerInstance; size_t StringPoolSize = 0; for (Uint32 i = 0; i < InstanceCount; ++i) @@ -82,30 +83,61 @@ public: StringPoolSize += strlen(pInstances[i].InstanceName) + 1; } - m_StringPool.Reserve(StringPoolSize, GetRawAllocator()); + this->m_StringPool.Reserve(StringPoolSize, GetRawAllocator()); Uint32 InstanceOffset = 0; for (Uint32 i = 0; i < InstanceCount; ++i) { auto& inst = pInstances[i]; - const char* NameCopy = m_StringPool.CopyString(inst.InstanceName); + const char* NameCopy = this->m_StringPool.CopyString(inst.InstanceName); InstanceDesc Desc = {}; Desc.ContributionToHitGroupIndex = inst.ContributionToHitGroupIndex; - Desc.pBLAS = inst.pBLAS; + Desc.pBLAS = ValidatedCast(inst.pBLAS); + +#ifdef DILIGENT_DEVELOPMENT + Desc.Version = Desc.pBLAS->GetVersion(); +#endif if (Desc.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) { Desc.ContributionToHitGroupIndex = InstanceOffset; auto& BLASDesc = Desc.pBLAS->GetDesc(); - InstanceOffset += (BLASDesc.TriangleCount + BLASDesc.BoxCount) * HitShadersPerInstance; + switch (this->m_Desc.BindingMode) + { + // clang-format off + case SHADER_BINDING_MODE_PER_GEOMETRY: InstanceOffset += (BLASDesc.TriangleCount + BLASDesc.BoxCount) * HitShadersPerInstance; break; + case SHADER_BINDING_MODE_PER_INSTANCE: InstanceOffset += HitShadersPerInstance; break; + case SHADER_BINDING_USER_DEFINED: UNEXPECTED("TLAS_INSTANCE_OFFSET_AUTO is not compatible with SHADER_BINDING_USER_DEFINED"); break; + default: UNEXPECTED("unknown ray tracing shader binding mode"); + // clang-format on + } } - bool IsUniqueName = m_Instances.emplace(NameCopy, Desc).second; + bool IsUniqueName = this->m_Instances.emplace(NameCopy, Desc).second; if (!IsUniqueName) LOG_ERROR_AND_THROW("Instance name must be unique!"); } + + VERIFY_EXPR(this->m_StringPool.GetRemainingSize() == 0); + } + + void CopyInstancceData(const TopLevelASBase& Src) + { + this->m_Instances.clear(); + this->m_StringPool.Release(); + this->m_StringPool.Reserve(Src.m_StringPool.GetReservedSize(), GetRawAllocator()); + this->m_HitShadersPerInstance = Src.m_HitShadersPerInstance; + this->m_Desc.BindingMode = Src.m_Desc.BindingMode; + + for (auto& SrcInst : Src.m_Instances) + { + const char* NameCopy = this->m_StringPool.CopyString(SrcInst.first.GetStr()); + this->m_Instances.emplace(NameCopy, SrcInst.second); + } + + VERIFY_EXPR(this->m_StringPool.GetRemainingSize() == 0); } virtual TLASInstanceDesc DILIGENT_CALL_TYPE GetInstanceDesc(const char* Name) const override final @@ -114,11 +146,11 @@ public: TLASInstanceDesc Result = {}; - auto iter = m_Instances.find(Name); - if (iter != m_Instances.end()) + auto iter = this->m_Instances.find(Name); + if (iter != this->m_Instances.end()) { Result.ContributionToHitGroupIndex = iter->second.ContributionToHitGroupIndex; - Result.pBLAS = iter->second.pBLAS; + Result.pBLAS = iter->second.pBLAS.RawPtr(); } else { @@ -150,6 +182,22 @@ public: return (this->m_State & State) == State; } +#ifdef DILIGENT_DEVELOPMENT + bool CheckBLASVersion() const + { + for (auto& NameAndInst : m_Instances) + { + auto& Inst = NameAndInst.second; + if (Inst.Version != Inst.pBLAS->GetVersion()) + { + LOG_ERROR_MESSAGE("Instance with name ('", NameAndInst.first.GetStr(), "') has BLAS that was changed after TLAS build, you must rebuild TLAS."); + return false; + } + } + return true; + } +#endif + protected: static void ValidateTopLevelASDesc(const TopLevelASDesc& Desc) { @@ -172,14 +220,19 @@ protected: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelAS, TDeviceObjectBase) protected: - RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN; + RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN; + Uint32 m_HitShadersPerInstance = 0; StringPool m_StringPool; struct InstanceDesc { - Uint32 ContributionToHitGroupIndex = 0; - mutable RefCntAutoPtr pBLAS; + Uint32 ContributionToHitGroupIndex = 0; + RefCntAutoPtr pBLAS; + +#ifdef DILIGENT_DEVELOPMENT + Uint32 Version = 0; +#endif }; std::unordered_map m_Instances; }; diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index 35e17e91..0cb7fe7d 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -741,7 +741,7 @@ DILIGENT_TYPED_ENUM(RAYTRACING_INSTANCE_FLAGS, Uint8) /// geometries referenced by this instance. This behavior can be overridden by the SPIR-V OpaqueKHR ray flag. RAYTRACING_INSTANCE_FORCE_NO_OPAQUE = 0x08, - RAYTRACING_INSTANCE_FLAGS_LAST = 0x08 + RAYTRACING_INSTANCE_FLAGS_LAST = RAYTRACING_INSTANCE_FORCE_NO_OPAQUE }; DEFINE_FLAG_ENUM_OPERATORS(RAYTRACING_INSTANCE_FLAGS) @@ -757,7 +757,7 @@ DILIGENT_TYPED_ENUM(COPY_AS_MODE, Uint8) // after the build of the acceleration structure specified by src. //COPY_AS_MODE_COMPACT, - COPY_AS_MODE_LAST = 0, + COPY_AS_MODE_LAST = COPY_AS_MODE_CLONE, }; /// Defines geometry flags for ray tracing. @@ -775,7 +775,7 @@ DILIGENT_TYPED_ENUM(RAYTRACING_GEOMETRY_FLAGS, Uint8) /// If this bit is absent an implementation may invoke the any-hit shader more than once for this geometry. RAYTRACING_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION = 0x02, - RAYTRACING_GEOMETRY_FLAGS_LAST = 0x02 + RAYTRACING_GEOMETRY_FLAGS_LAST = RAYTRACING_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION }; DEFINE_FLAG_ENUM_OPERATORS(RAYTRACING_GEOMETRY_FLAGS) @@ -910,6 +910,35 @@ static const Uint32 TLAS_INSTANCE_OFFSET_AUTO = ~0u; /// AZ TODO static const Uint32 TLAS_INSTANCE_DATA_SIZE = 64; +/// AZ TODO +struct InstanceMatrix +{ + /// rotation translation + /// (0 1 2) [ 3] + /// (4 5 6) [ 7] + /// (8 9 10) [11] + float data [3][4]; + +#if DILIGENT_CPP_INTERFACE + /// AZ TODO + InstanceMatrix() noexcept : + data{{1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}} + {} + + InstanceMatrix(const InstanceMatrix&) noexcept = default; + + InstanceMatrix& SetTranslation(float x, float y, float z) noexcept + { + data[0][3] = x; + data[1][3] = y; + data[2][3] = z; + return *this; + } +#endif +}; +typedef struct InstanceMatrix InstanceMatrix; /// AZ TODO struct TLASBuildInstanceData @@ -921,7 +950,7 @@ struct TLASBuildInstanceData IBottomLevelAS* pBLAS DEFAULT_INITIALIZER(nullptr); // can be null to deactive instance /// AZ TODO - float Transform[3][4] DEFAULT_INITIALIZER({}); + InstanceMatrix Transform; /// AZ TODO Uint32 CustomId DEFAULT_INITIALIZER(0); // 24 bits, in shader: gl_InstanceCustomIndexNV for GLSL, InstanceID() for HLSL diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index 4115a9d1..ebec8344 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -299,8 +299,11 @@ typedef struct RayTracingProceduralHitShaderGroup RayTracingProceduralHitShaderG /// AZ TODO struct RayTracingPipelineDesc { + // Size of the additional data passed to the shader. + Uint16 ShaderRecordSize DEFAULT_INITIALIZER(0); + /// AZ TODO - Uint8 MaxRecursionDepth DEFAULT_INITIALIZER(0); // must be 0..31 (check current device limits) + Uint8 MaxRecursionDepth DEFAULT_INITIALIZER(0); // must be 0..31 (check current device limits) }; typedef struct RayTracingPipelineDesc RayTracingPipelineDesc; @@ -438,7 +441,7 @@ typedef struct ComputePipelineStateCreateInfo ComputePipelineStateCreateInfo; struct RayTracingPipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo) /// AZ TODO - RayTracingPipelineDesc RayTracingPipeline; + RayTracingPipelineDesc RayTracingPipeline; /// AZ TODO const RayTracingGeneralShaderGroup* pGeneralShaders DEFAULT_INITIALIZER(nullptr); @@ -457,6 +460,10 @@ struct RayTracingPipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo /// AZ TODO Uint16 ProceduralHitShaderCount DEFAULT_INITIALIZER(0); + + /// Direct3D12 only: set name of constant buffer that will be used by local root signature. + /// Ignored if RayTracingPipelineDesc::ShaderRecordSize is zero. + const char* ShaderRecordName DEFAULT_INITIALIZER(nullptr); }; typedef struct RayTracingPipelineStateCreateInfo RayTracingPipelineStateCreateInfo; diff --git a/Graphics/GraphicsEngine/interface/ShaderBindingTable.h b/Graphics/GraphicsEngine/interface/ShaderBindingTable.h index 2a5e587a..d6f0740f 100644 --- a/Graphics/GraphicsEngine/interface/ShaderBindingTable.h +++ b/Graphics/GraphicsEngine/interface/ShaderBindingTable.h @@ -51,9 +51,6 @@ struct ShaderBindingTableDesc DILIGENT_DERIVE(DeviceObjectAttribs) /// AZ TODO IPipelineState* pPSO DEFAULT_INITIALIZER(nullptr); - - // Size of the additional data passed to the shader, maximum size is 4064 bytes. - Uint32 ShaderRecordSize DEFAULT_INITIALIZER(0); /// AZ TODO Uint32 HitShadersPerInstance DEFAULT_INITIALIZER(1); @@ -114,7 +111,7 @@ DILIGENT_BEGIN_INTERFACE(IShaderBindingTable, IDeviceObject) #endif /// AZ TODO - VIRTUAL void METHOD(Verify)(THIS) CONST PURE; + VIRTUAL Bool METHOD(Verify)(THIS) CONST PURE; /// AZ TODO VIRTUAL void METHOD(Reset)(THIS_ diff --git a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp index 5e69da8e..5be505a1 100644 --- a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp @@ -61,7 +61,7 @@ struct DeviceContextD3D11ImplTraits using FramebufferType = FramebufferD3D11Impl; using RenderPassType = RenderPassD3D11Impl; using BottomLevelASType = BottomLevelASBase; - using TopLevelASType = TopLevelASBase; + using TopLevelASType = TopLevelASBase; }; /// Device context implementation in Direct3D11 backend. diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp index 6a27a029..f336c6ff 100644 --- a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp @@ -144,8 +144,11 @@ private: void Destruct(); - CComPtr m_pd3d12PSO; - RootSignature m_RootSig; + void CreateLocalRootSignature(const RayTracingPipelineDesc& Desc); + + CComPtr m_pd3d12PSO; + RootSignature m_RootSig; + CComPtr m_LocalRootSignature; // Must be defined before default SRB SRBMemoryAllocator m_SRBMemAllocator; diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp index ab72e22a..636175d5 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp @@ -178,10 +178,8 @@ public: ShaderVersion GetMaxShaderModel() const; D3D_FEATURE_LEVEL GetD3DFeatureLevel() const; - static Uint32 GetShaderGroupHandleSize() - { - return D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; - } + static Uint32 GetShaderGroupHandleSize() { return D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; } + static Uint32 GetMaxShaderRecordStride() { return D3D12_RAYTRACING_MAX_SHADER_RECORD_STRIDE; } private: template diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp index e866c6f2..daf84d14 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp @@ -54,10 +54,6 @@ public: virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; - virtual void DILIGENT_CALL_TYPE Verify() const override; - - virtual void DILIGENT_CALL_TYPE Reset(const ShaderBindingTableDesc& Desc) override; - virtual void DILIGENT_CALL_TYPE ResetHitGroups(Uint32 HitShadersPerInstance) override; virtual void DILIGENT_CALL_TYPE BindAll(const BindAllAttribs& Attribs) override; @@ -69,9 +65,6 @@ public: D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE& HitShaderBindingTable, D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE& CallableShaderBindingTable) override; -private: - void ValidateDesc(const ShaderBindingTableDesc& Desc) const; - private: RefCntAutoPtr m_pBuffer; }; diff --git a/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp index 8eccf530..c61ab368 100644 --- a/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp @@ -33,6 +33,7 @@ #include "TopLevelASD3D12.h" #include "RenderDeviceD3D12.h" #include "TopLevelASBase.hpp" +#include "BottomLevelASD3D12Impl.hpp" #include "D3D12ResourceBase.hpp" #include "RenderDeviceD3D12Impl.hpp" @@ -40,10 +41,10 @@ namespace Diligent { /// Top-level acceleration structure object implementation in Direct3D12 backend. -class TopLevelASD3D12Impl final : public TopLevelASBase, public D3D12ResourceBase +class TopLevelASD3D12Impl final : public TopLevelASBase, public D3D12ResourceBase { public: - using TTopLevelASBase = TopLevelASBase; + using TTopLevelASBase = TopLevelASBase; TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, class RenderDeviceD3D12Impl* pDeviceD3D12, diff --git a/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h b/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h index 4b0835cd..aa50251a 100644 --- a/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h @@ -65,6 +65,7 @@ DILIGENT_END_INTERFACE #if DILIGENT_C_INTERFACE +# define IShaderBindingTableD3D12_GetD3D12AddressRangeAndStride(This, ...) CALL_IFACE_METHOD(ShaderBindingTableD3D12, GetD3D12AddressRangeAndStride, This, __VA_ARGS__) #endif diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 3cd896ac..0adcaa59 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -2198,8 +2198,6 @@ void DeviceContextD3D12Impl::TransitionOrVerifyTLASState(CommandContext& RESOURCE_STATE RequiredState, const char* OperationName) { - // AZ TODO: transit BLAS state too? - if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { if (TLAS.IsInKnownState() && !TLAS.CheckState(RequiredState)) @@ -2210,6 +2208,11 @@ void DeviceContextD3D12Impl::TransitionOrVerifyTLASState(CommandContext& { DvpVerifyTLASState(TLAS, RequiredState, OperationName); } + + if (RequiredState & RESOURCE_STATE_RAY_TRACING) + { + TLAS.CheckBLASVersion(); + } #endif } @@ -2318,6 +2321,8 @@ void DeviceContextD3D12Impl::BuildBLAS(const BLASBuildAttribs& Attribs) d3d12Tris.VertexBuffer.StartAddress = pVB->GetGPUAddress() + SrcTris.VertexOffset; d3d12Tris.VertexBuffer.StrideInBytes = SrcTris.VertexStride; + TransitionOrVerifyBufferState(CmdCtx, *pVB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + if (SrcTris.pIndexBuffer) { auto* const pIB = ValidatedCast(SrcTris.pIndexBuffer); @@ -2389,6 +2394,10 @@ void DeviceContextD3D12Impl::BuildBLAS(const BLASBuildAttribs& Attribs) CmdCtx.AsGraphicsContext4().BuildRaytracingAccelerationStructure(Desc, 0, nullptr); ++m_State.NumCommands; + +#ifdef DILIGENT_DEVELOPMENT + pBLASD12->UpdateVersion(); +#endif } void DeviceContextD3D12Impl::BuildTLAS(const TLASBuildAttribs& Attribs) @@ -2401,7 +2410,6 @@ void DeviceContextD3D12Impl::BuildTLAS(const TLASBuildAttribs& Attribs) auto* pTLASD12 = ValidatedCast(Attribs.pTLAS); auto* pScratchD12 = ValidatedCast(Attribs.pScratchBuffer); auto* pInstancesD12 = ValidatedCast(Attribs.pInstanceBuffer); - //auto& TLASDesc = pTLASD12->GetDesc(); auto& CmdCtx = GetCmdContext(); const char* OpName = "Build TopLevelAS (DeviceContextD3D12Impl::BuildTLAS)"; @@ -2423,7 +2431,7 @@ void DeviceContextD3D12Impl::BuildTLAS(const TLASBuildAttribs& Attribs) auto* const pBLASD12 = ValidatedCast(Inst.pBLAS); static_assert(sizeof(d3d12Inst.Transform) == sizeof(Inst.Transform), "size mismatch"); - std::memcpy(&d3d12Inst.Transform, Inst.Transform, sizeof(d3d12Inst.Transform)); + std::memcpy(&d3d12Inst.Transform, Inst.Transform.data, sizeof(d3d12Inst.Transform)); d3d12Inst.InstanceID = Inst.CustomId; d3d12Inst.InstanceContributionToHitGroupIndex = pTLASD12->GetInstanceDesc(Inst.InstanceName).ContributionToHitGroupIndex; // AZ TODO: optimize @@ -2458,7 +2466,20 @@ void DeviceContextD3D12Impl::CopyBLAS(const CopyBLASAttribs& Attribs) if (!TDeviceContextBase::CopyBLAS(Attribs, 0)) return; - // AZ TODO + auto* pSrcD3D12 = ValidatedCast(Attribs.pSrc); + auto* pDstD3D12 = ValidatedCast(Attribs.pDst); + auto& CmdCtx = GetCmdContext(); + + const char* OpName = "Copy BottomLevelAS (DeviceContextD3D12Impl::CopyBLAS)"; + TransitionOrVerifyBLASState(CmdCtx, *pSrcD3D12, Attribs.TransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyBLASState(CmdCtx, *pDstD3D12, Attribs.TransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + + CmdCtx.AsGraphicsContext4().CopyRaytracingAccelerationStructure(pSrcD3D12->GetGPUAddress(), pDstD3D12->GetGPUAddress(), D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_CLONE); + ++m_State.NumCommands; + +#ifdef DILIGENT_DEVELOPMENT + pDstD3D12->UpdateVersion(); +#endif } void DeviceContextD3D12Impl::CopyTLAS(const CopyTLASAttribs& Attribs) @@ -2466,7 +2487,18 @@ void DeviceContextD3D12Impl::CopyTLAS(const CopyTLASAttribs& Attribs) if (!TDeviceContextBase::CopyTLAS(Attribs, 0)) return; - // AZ TODO + auto* pSrcD3D12 = ValidatedCast(Attribs.pSrc); + auto* pDstD3D12 = ValidatedCast(Attribs.pDst); + auto& CmdCtx = GetCmdContext(); + + pDstD3D12->CopyInstancceData(*pSrcD3D12); + + const char* OpName = "Copy BottomLevelAS (DeviceContextD3D12Impl::CopyTLAS)"; + TransitionOrVerifyTLASState(CmdCtx, *pSrcD3D12, Attribs.TransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyTLASState(CmdCtx, *pDstD3D12, Attribs.TransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + + CmdCtx.AsGraphicsContext4().CopyRaytracingAccelerationStructure(pSrcD3D12->GetGPUAddress(), pDstD3D12->GetGPUAddress(), D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_CLONE); + ++m_State.NumCommands; } void DeviceContextD3D12Impl::TraceRays(const TraceRaysAttribs& Attribs) diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp index 405f6d4b..b1fe19fe 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -224,7 +224,7 @@ void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& CreateI } template -void GetShaderIdentifiers(ID3D12StateObject* pSO, +void GetShaderIdentifiers(ID3D12DeviceChild* pSO, const RayTracingPipelineStateCreateInfo& CreateInfo, const TNameToGroupIndexMap& NameToGroupIndex, Uint8* ShaderData) @@ -625,6 +625,8 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* { try { + CreateLocalRootSignature(CreateInfo.RayTracingPipeline); + TShaderStages ShaderStages; std::vector Subobjects; DynamicLinearAllocator TempPool{GetRawAllocator(), 4 << 10}; @@ -640,21 +642,21 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* D3D12_GLOBAL_ROOT_SIGNATURE GlobalRoot = {m_RootSig.GetD3D12RootSignature()}; Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE, &GlobalRoot}); + D3D12_LOCAL_ROOT_SIGNATURE LocalRoot = {m_LocalRootSignature}; + if (m_LocalRootSignature) + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE, &LocalRoot}); + D3D12_STATE_OBJECT_DESC RTPipelineDesc = {}; RTPipelineDesc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; RTPipelineDesc.NumSubobjects = static_cast(Subobjects.size()); RTPipelineDesc.pSubobjects = Subobjects.data(); - CComPtr pSO; - auto pd3d12Device = pDeviceD3D12->GetD3D12Device5(); - HRESULT hr = pd3d12Device->CreateStateObject(&RTPipelineDesc, IID_PPV_ARGS(&pSO)); + HRESULT hr = pd3d12Device->CreateStateObject(&RTPipelineDesc, IID_PPV_ARGS(&m_pd3d12PSO)); if (FAILED(hr)) LOG_ERROR_AND_THROW("Failed to create ray tracing state object"); - m_pd3d12PSO = pSO; - - GetShaderIdentifiers(pSO, CreateInfo, m_pRayTracingPipelineData->NameToGroupIndex, m_pRayTracingPipelineData->Shaders); + GetShaderIdentifiers(m_pd3d12PSO, CreateInfo, m_pRayTracingPipelineData->NameToGroupIndex, m_pRayTracingPipelineData->Shaders); if (*m_Desc.Name != 0) { @@ -672,6 +674,35 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* } } +void PipelineStateD3D12Impl::CreateLocalRootSignature(const RayTracingPipelineDesc& Desc) +{ + // AZ TODO + /*if (Desc.ShaderRecordSize == 0) + return; + + D3D12_ROOT_SIGNATURE_DESC d3d12RootSignatureDesc = {}; + D3D12_ROOT_PARAMETER d3d12Params = {}; + + d3d12Params.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + d3d12Params.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + d3d12Params.Constants.Num32BitValues = Desc.ShaderRecordSize / 4; + d3d12Params.Constants.RegisterSpace = Desc.LocalRootRegisterSpace; + d3d12Params.Constants.ShaderRegister = 0; + + d3d12RootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; + d3d12RootSignatureDesc.NumParameters = 1; + d3d12RootSignatureDesc.pParameters = &d3d12Params; + + CComPtr signature; + auto hr = D3D12SerializeRootSignature(&d3d12RootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr); + CHECK_D3D_RESULT_THROW(hr, "Failed to serialize root signature"); + + auto pd3d12Device = GetDevice()->GetD3D12Device(); + + hr = pd3d12Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_LocalRootSignature)); + CHECK_D3D_RESULT_THROW(hr, "Failed to create root signature");*/ +} + PipelineStateD3D12Impl::~PipelineStateD3D12Impl() { Destruct(); diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp index d0db2201..e6af12c8 100644 --- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp @@ -705,7 +705,7 @@ __forceinline void TransitionResource(CommandContext& Ctx, { VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); auto* pTLASD3D12 = Res.pObject.RawPtr(); - if (pTLASD3D12->IsInKnownState() && !pTLASD3D12->CheckState(RESOURCE_STATE_RAY_TRACING)) + if (pTLASD3D12->IsInKnownState()) Ctx.TransitionResource(pTLASD3D12, RESOURCE_STATE_RAY_TRACING); } break; diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp index d352caf0..d71d98b7 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp @@ -44,9 +44,6 @@ ShaderBindingTableD3D12Impl::ShaderBindingTableD3D12Impl(IReferenceCounters* bool bIsDeviceInternal) : TShaderBindingTableBase{pRefCounters, pDeviceD3D12, Desc, bIsDeviceInternal} { - ValidateDesc(Desc); - - m_ShaderRecordStride = m_Desc.ShaderRecordSize + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; } ShaderBindingTableD3D12Impl::~ShaderBindingTableD3D12Impl() @@ -55,43 +52,6 @@ ShaderBindingTableD3D12Impl::~ShaderBindingTableD3D12Impl() IMPLEMENT_QUERY_INTERFACE(ShaderBindingTableD3D12Impl, IID_ShaderBindingTableD3D12, TShaderBindingTableBase) -void ShaderBindingTableD3D12Impl::ValidateDesc(const ShaderBindingTableDesc& Desc) const -{ - if (Desc.ShaderRecordSize + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES > D3D12_RAYTRACING_MAX_SHADER_RECORD_STRIDE) - { - LOG_ERROR_AND_THROW("Description of Shader binding table '", (Desc.Name ? Desc.Name : ""), - "' is invalid: ShaderRecordSize is too big, max size is: ", D3D12_RAYTRACING_MAX_SHADER_RECORD_STRIDE - D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES); - } -} - -void ShaderBindingTableD3D12Impl::Verify() const -{ - // AZ TODO -} - -void ShaderBindingTableD3D12Impl::Reset(const ShaderBindingTableDesc& Desc) -{ - m_RayGenShaderRecord.clear(); - m_MissShadersRecord.clear(); - m_CallableShadersRecord.clear(); - m_HitGroupsRecord.clear(); - m_Changed = true; - - try - { - ValidateShaderBindingTableDesc(Desc); - ValidateDesc(Desc); - } - catch (const std::runtime_error&) - { - // AZ TODO - return; - } - - m_Desc = Desc; - m_ShaderRecordStride = m_Desc.ShaderRecordSize + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; -} - void ShaderBindingTableD3D12Impl::ResetHitGroups(Uint32 HitShadersPerInstance) { // AZ TODO diff --git a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp index 0b2154e6..32055367 100644 --- a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp @@ -56,7 +56,7 @@ struct DeviceContextGLImplTraits using FramebufferType = FramebufferGLImpl; using RenderPassType = RenderPassGLImpl; using BottomLevelASType = BottomLevelASBase; - using TopLevelASType = TopLevelASBase; + using TopLevelASType = TopLevelASBase; }; /// Device context implementation in OpenGL backend. diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index e13f1a76..5440a6c8 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp @@ -201,6 +201,10 @@ public: { return GetPhysicalDevice().GetExtProperties().RayTracing.shaderGroupHandleSize; } + Uint32 GetMaxShaderRecordStride() const + { + return GetPhysicalDevice().GetExtProperties().RayTracing.maxShaderGroupStride; + } private: template diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp index 1b2db950..cef50a4e 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp @@ -51,10 +51,6 @@ public: bool bIsDeviceInternal = false); ~ShaderBindingTableVkImpl(); - virtual void DILIGENT_CALL_TYPE Verify() const override; - - virtual void DILIGENT_CALL_TYPE Reset(const ShaderBindingTableDesc& Desc) override; - virtual void DILIGENT_CALL_TYPE ResetHitGroups(Uint32 HitShadersPerInstance) override; virtual void DILIGENT_CALL_TYPE BindAll(const BindAllAttribs& Attribs) override; @@ -67,9 +63,6 @@ public: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderBindingTableVk, TShaderBindingTableBase); -private: - void ValidateDesc(const ShaderBindingTableDesc& Desc) const; - private: RefCntAutoPtr m_pBuffer; }; diff --git a/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp index b2801eca..0f8a94c8 100644 --- a/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp @@ -34,15 +34,16 @@ #include "RenderDeviceVkImpl.hpp" #include "TopLevelASVk.h" #include "TopLevelASBase.hpp" +#include "BottomLevelASVkImpl.hpp" #include "VulkanUtilities/VulkanObjectWrappers.hpp" namespace Diligent { -class TopLevelASVkImpl final : public TopLevelASBase +class TopLevelASVkImpl final : public TopLevelASBase { public: - using TTopLevelASBase = TopLevelASBase; + using TTopLevelASBase = TopLevelASBase; TopLevelASVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 69a3a1ba..a77fb96d 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -2334,6 +2334,22 @@ void DeviceContextVkImpl::TransitionImageLayout(ITexture* pTexture, VkImageLayou } } +namespace +{ +NODISCARD inline bool ResourceStateHasWriteAccess(RESOURCE_STATE State) +{ + static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag"); + constexpr RESOURCE_STATE WriteAccessStates = + RESOURCE_STATE_RENDER_TARGET | + RESOURCE_STATE_UNORDERED_ACCESS | + RESOURCE_STATE_COPY_DEST | + RESOURCE_STATE_RESOLVE_DEST | + RESOURCE_STATE_BUILD_AS_WRITE; + + return State & WriteAccessStates; +} +} // namespace + void DeviceContextVkImpl::TransitionTextureState(TextureVkImpl& TextureVk, RESOURCE_STATE OldState, RESOURCE_STATE NewState, @@ -2396,17 +2412,22 @@ void DeviceContextVkImpl::TransitionTextureState(TextureVkImpl& Textur pSubresRange->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } - // Note that when both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier - // to make sure that all UAV writes are complete and visible. + // Always add barrier after writes. + const bool AfterWrite = ResourceStateHasWriteAccess(OldState); + auto OldLayout = ResourceStateToVkImageLayout(OldState); auto NewLayout = ResourceStateToVkImageLayout(NewState); auto OldStages = ResourceStateFlagsToVkPipelineStageFlags(OldState, m_CommandBuffer.GetEnabledShaderStages()); auto NewStages = ResourceStateFlagsToVkPipelineStageFlags(NewState, m_CommandBuffer.GetEnabledShaderStages()); - m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, *pSubresRange, OldStages, NewStages); - if (UpdateTextureState) + + if (((OldState & NewState) != NewState) || OldLayout != NewLayout || AfterWrite) { - TextureVk.SetState(NewState); - VERIFY_EXPR(TextureVk.GetLayout() == NewLayout); + m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, *pSubresRange, OldStages, NewStages); + if (UpdateTextureState) + { + TextureVk.SetState(NewState); + VERIFY_EXPR(TextureVk.GetLayout() == NewLayout); + } } } @@ -2421,10 +2442,7 @@ void DeviceContextVkImpl::TransitionOrVerifyTextureState(TextureVkImpl& VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); if (Texture.IsInKnownState()) { - if (!Texture.CheckState(RequiredState)) - { - TransitionTextureState(Texture, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } + TransitionTextureState(Texture, RESOURCE_STATE_UNKNOWN, RequiredState, true); VERIFY_EXPR(Texture.GetLayout() == ExpectedLayout); } } @@ -2489,9 +2507,10 @@ void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE } } - // When both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier - // to make sure that all UAV writes are complete and visible. - if (((OldState & NewState) != NewState) || NewState == RESOURCE_STATE_UNORDERED_ACCESS || NewState == RESOURCE_STATE_BUILD_AS_WRITE) + // Always add barrier after writes. + const bool AfterWrite = ResourceStateHasWriteAccess(OldState); + + if (((OldState & NewState) != NewState) || AfterWrite) { DEV_CHECK_ERR(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer"); VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0); @@ -2521,10 +2540,7 @@ void DeviceContextVkImpl::TransitionOrVerifyBufferState(BufferVkImpl& VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); if (Buffer.IsInKnownState()) { - if (!Buffer.CheckState(RequiredState)) - { - TransitionBufferState(Buffer, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } + TransitionBufferState(Buffer, RESOURCE_STATE_UNKNOWN, RequiredState, true); VERIFY_EXPR(Buffer.CheckAccessFlags(ExpectedAccessFlags)); } } @@ -2564,7 +2580,10 @@ void DeviceContextVkImpl::TransitionBLASState(BottomLevelASVkImpl& BLAS, } } - if ((OldState & NewState) != NewState) + // Always add barrier after writes. + const bool AfterWrite = ResourceStateHasWriteAccess(OldState); + + if ((OldState & NewState) != NewState || AfterWrite) { EnsureVkCmdBuffer(); auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); @@ -2584,8 +2603,6 @@ void DeviceContextVkImpl::TransitionTLASState(TopLevelASVkImpl& TLAS, RESOURCE_STATE NewState, bool UpdateInternalState) { - // AZ TODO: transit BLAS state too? - VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); if (OldState == RESOURCE_STATE_UNKNOWN) { @@ -2609,7 +2626,10 @@ void DeviceContextVkImpl::TransitionTLASState(TopLevelASVkImpl& TLAS, } } - if ((OldState & NewState) != NewState) + // Always add barrier after writes. + const bool AfterWrite = ResourceStateHasWriteAccess(OldState); + + if ((OldState & NewState) != NewState || AfterWrite) { EnsureVkCmdBuffer(); auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); @@ -2634,10 +2654,7 @@ void DeviceContextVkImpl::TransitionOrVerifyBLASState(BottomLevelASVkImpl& VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); if (BLAS.IsInKnownState()) { - if (!BLAS.CheckState(RequiredState)) - { - TransitionBLASState(BLAS, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } + TransitionBLASState(BLAS, RESOURCE_STATE_UNKNOWN, RequiredState, true); } } #ifdef DILIGENT_DEVELOPMENT @@ -2658,10 +2675,7 @@ void DeviceContextVkImpl::TransitionOrVerifyTLASState(TopLevelASVkImpl& VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); if (TLAS.IsInKnownState()) { - if (!TLAS.CheckState(RequiredState)) - { - TransitionTLASState(TLAS, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } + TransitionTLASState(TLAS, RESOURCE_STATE_UNKNOWN, RequiredState, true); } } #ifdef DILIGENT_DEVELOPMENT @@ -2669,6 +2683,11 @@ void DeviceContextVkImpl::TransitionOrVerifyTLASState(TopLevelASVkImpl& { DvpVerifyTLASState(TLAS, RequiredState, OperationName); } + + if (RequiredState & RESOURCE_STATE_RAY_TRACING) + { + TLAS.CheckBLASVersion(); + } #endif } @@ -2718,13 +2737,13 @@ void DeviceContextVkImpl::TransitionResourceStates(Uint32 BarrierCount, StateTra { TransitionBufferState(*pBuffer, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); } - else if (RefCntAutoPtr pBLAS{Barrier.pResource, IID_BottomLevelAS}) + else if (RefCntAutoPtr pBottomLevelAS{Barrier.pResource, IID_BottomLevelAS}) { - TransitionBLASState(*pBLAS, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); + TransitionBLASState(*pBottomLevelAS, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); } - else if (RefCntAutoPtr pTLAS{Barrier.pResource, IID_TopLevelAS}) + else if (RefCntAutoPtr pTopLevelAS{Barrier.pResource, IID_TopLevelAS}) { - TransitionTLASState(*pTLAS, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); + TransitionTLASState(*pTopLevelAS, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); } else { @@ -2808,7 +2827,7 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) const char* OpName = "Build BottomLevelAS (DeviceContextVkImpl::BuildBLAS)"; TransitionOrVerifyBLASState(*pBLASVk, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); - TransitionOrVerifyBufferState(*pScratchVk, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, VkAccessFlagBits(0), OpName); + TransitionOrVerifyBufferState(*pScratchVk, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, OpName); VkAccelerationStructureBuildGeometryInfoKHR Info = {}; std::vector Offsets; @@ -2845,7 +2864,7 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) vkTris.vertexStride = SrcTris.VertexStride; vkTris.vertexData.deviceAddress = pVB->GetVkDeviceAddress() + SrcTris.VertexOffset; - TransitionOrVerifyBufferState(*pVB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, static_cast(0), OpName); + TransitionOrVerifyBufferState(*pVB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, OpName); if (SrcTris.pIndexBuffer) { @@ -2854,7 +2873,7 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) vkTris.indexData.deviceAddress = pIB->GetVkDeviceAddress() + SrcTris.IndexOffset; off.primitiveCount = SrcTris.IndexCount / 3; - TransitionOrVerifyBufferState(*pIB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, static_cast(0), OpName); + TransitionOrVerifyBufferState(*pIB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, OpName); } else { @@ -2870,7 +2889,7 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) auto* const pTB = ValidatedCast(SrcTris.pTransformBuffer); vkTris.transformData.deviceAddress = pTB->GetVkDeviceAddress() + SrcTris.TransformBufferOffset; - TransitionOrVerifyBufferState(*pTB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VkAccessFlagBits(0), OpName); + TransitionOrVerifyBufferState(*pTB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, OpName); } else { @@ -2913,7 +2932,7 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) vkAABBs.stride = SrcBoxes.BoxStride; vkAABBs.data.deviceAddress = pBB->GetVkDeviceAddress() + SrcBoxes.BoxOffset; - TransitionOrVerifyBufferState(*pBB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VkAccessFlagBits(0), OpName); + TransitionOrVerifyBufferState(*pBB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, OpName); off.firstVertex = 0; off.transformOffset = 0; @@ -2939,6 +2958,10 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) EnsureVkCmdBuffer(); m_CommandBuffer.BuildAccelerationStructure(1, &Info, &OffsetsPtr); ++m_State.NumCommands; + +#ifdef DILIGENT_DEVELOPMENT + pBLASVk->UpdateVersion(); +#endif } void DeviceContextVkImpl::BuildTLAS(const TLASBuildAttribs& Attribs) @@ -2964,7 +2987,7 @@ void DeviceContextVkImpl::BuildTLAS(const TLASBuildAttribs& Attribs) const char* OpName = "Build TopLevelAS (DeviceContextVkImpl::BuildTLAS)"; TransitionOrVerifyTLASState(*pTLASVk, Attribs.TLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); - TransitionOrVerifyBufferState(*pScratchVk, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, VkAccessFlagBits(0), OpName); + TransitionOrVerifyBufferState(*pScratchVk, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, OpName); pTLASVk->SetInstanceData(Attribs.pInstances, Attribs.InstanceCount, Attribs.HitShadersPerInstance); @@ -2981,7 +3004,7 @@ void DeviceContextVkImpl::BuildTLAS(const TLASBuildAttribs& Attribs) auto* const pBLASVk = ValidatedCast(Inst.pBLAS); static_assert(sizeof(vkASInst.transform) == sizeof(Inst.Transform), "size mismatch"); - std::memcpy(&vkASInst.transform, Inst.Transform, sizeof(vkASInst.transform)); + std::memcpy(&vkASInst.transform, Inst.Transform.data, sizeof(vkASInst.transform)); vkASInst.instanceCustomIndex = Inst.CustomId; vkASInst.instanceShaderBindingTableRecordOffset = pTLASVk->GetInstanceDesc(Inst.InstanceName).ContributionToHitGroupIndex; // AZ TODO: optimize @@ -2994,7 +3017,7 @@ void DeviceContextVkImpl::BuildTLAS(const TLASBuildAttribs& Attribs) UpdateBufferRegion(pInstancesVk, Attribs.InstanceBufferOffset, Size, TmpSpace.vkBuffer, TmpSpace.AlignedOffset, Attribs.InstanceBufferTransitionMode); } - TransitionOrVerifyBufferState(*pInstancesVk, Attribs.InstanceBufferTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VkAccessFlagBits(0), OpName); + TransitionOrVerifyBufferState(*pInstancesVk, Attribs.InstanceBufferTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, OpName); VkAccelerationStructureBuildGeometryInfoKHR vkASBuildInfo = {}; VkAccelerationStructureBuildOffsetInfoKHR vkASBuildOffset = {}; @@ -3060,6 +3083,10 @@ void DeviceContextVkImpl::CopyBLAS(const CopyBLASAttribs& Attribs) m_CommandBuffer.CopyAccelerationStructure(Info); ++m_State.NumCommands; + +#ifdef DILIGENT_DEVELOPMENT + pDstVk->UpdateVersion(); +#endif } void DeviceContextVkImpl::CopyTLAS(const CopyTLASAttribs& Attribs) @@ -3077,6 +3104,8 @@ void DeviceContextVkImpl::CopyTLAS(const CopyTLASAttribs& Attribs) auto* pSrcVk = ValidatedCast(Attribs.pSrc); auto* pDstVk = ValidatedCast(Attribs.pDst); + pDstVk->CopyInstancceData(*pSrcVk); + VkCopyAccelerationStructureInfoKHR Info = {}; Info.sType = VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR; diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 36ca3a42..1cac2b6f 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -758,10 +758,16 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* { try { + const auto& LogicalDevice = GetDevice()->GetLogicalDevice(); + const auto ShaderGroupHandleSize = pDeviceVk->GetShaderGroupHandleSize(); + + if (LogicalDevice.GetEnabledExtFeatures().RayTracing.rayTracing == VK_FALSE) + LOG_ERROR_AND_THROW("Ray tracing is not supported by this device"); + std::vector vkShaderStages; std::vector ShaderModules; - std::vector ShaderGroups; + InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules, [&](const RayTracingPipelineStateCreateInfo& CreateInfo, LinearAllocator& MemPool, TShaderStages& ShaderStages) // { @@ -773,9 +779,6 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* CreateRayTracingPipeline(pDeviceVk, vkShaderStages, ShaderGroups, m_PipelineLayout, m_Desc, GetRayTracingPipelineDesc(), m_Pipeline); - const auto& LogicalDevice = GetDevice()->GetLogicalDevice(); - const auto ShaderGroupHandleSize = pDeviceVk->GetShaderGroupHandleSize(); - auto err = LogicalDevice.GetRayTracingShaderGroupHandles(m_Pipeline, 0, static_cast(ShaderGroups.size()), ShaderGroupHandleSize, &m_pRayTracingPipelineData->Shaders[0]); VERIFY(err == VK_SUCCESS, "Failed to get shader group handles"); (void)err; diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp index 6f5091e0..3940769f 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp @@ -39,57 +39,12 @@ ShaderBindingTableVkImpl::ShaderBindingTableVkImpl(IReferenceCounters* bool bIsDeviceInternal) : TShaderBindingTableBase{pRefCounters, pRenderDeviceVk, Desc, bIsDeviceInternal} { - ValidateDesc(Desc); - - const auto& RTLimits = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing; - m_ShaderRecordStride = m_Desc.ShaderRecordSize + RTLimits.shaderGroupHandleSize; } ShaderBindingTableVkImpl::~ShaderBindingTableVkImpl() { } -void ShaderBindingTableVkImpl::ValidateDesc(const ShaderBindingTableDesc& Desc) const -{ - const auto& RTLimits = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing; - - if (Desc.ShaderRecordSize + RTLimits.shaderGroupHandleSize > RTLimits.maxShaderGroupStride) - { - LOG_ERROR_AND_THROW("Description of Shader binding table '", (Desc.Name ? Desc.Name : ""), - "' is invalid: ShaderRecordSize is too big, max size is: ", RTLimits.maxShaderGroupStride - RTLimits.shaderGroupHandleSize); - } -} - -void ShaderBindingTableVkImpl::Verify() const -{ - // AZ TODO -} - -void ShaderBindingTableVkImpl::Reset(const ShaderBindingTableDesc& Desc) -{ - m_RayGenShaderRecord.clear(); - m_MissShadersRecord.clear(); - m_CallableShadersRecord.clear(); - m_HitGroupsRecord.clear(); - m_Changed = true; - - try - { - ValidateShaderBindingTableDesc(Desc); - ValidateDesc(Desc); - } - catch (const std::runtime_error&) - { - // AZ TODO - return; - } - - m_Desc = Desc; - - const auto& RTLimits = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing; - m_ShaderRecordStride = m_Desc.ShaderRecordSize + RTLimits.shaderGroupHandleSize; -} - void ShaderBindingTableVkImpl::ResetHitGroups(Uint32 HitShadersPerInstance) { // AZ TODO diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp index 8101fefc..27e5ee72 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp @@ -166,10 +166,9 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) { constexpr RESOURCE_STATE RequiredState = RESOURCE_STATE_CONSTANT_BUFFER; VERIFY_EXPR((ResourceStateFlagsToVkAccessFlags(RequiredState) & VK_ACCESS_UNIFORM_READ_BIT) == VK_ACCESS_UNIFORM_READ_BIT); - const bool IsInRequiredState = pBufferVk->CheckState(RequiredState); if (VerifyOnly) { - if (!IsInRequiredState) + if (!pBufferVk->CheckState(RequiredState)) { LOG_ERROR_MESSAGE("State of buffer '", pBufferVk->GetDesc().Name, "' is incorrect. Required state: ", GetResourceStateString(RequiredState), ". Actual state: ", @@ -181,10 +180,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) } else { - if (!IsInRequiredState) - { - pCtxVkImpl->TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } + pCtxVkImpl->TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); VERIFY_EXPR(pBufferVk->CheckAccessFlags(VK_ACCESS_UNIFORM_READ_BIT)); } } @@ -211,11 +207,10 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) (VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); VERIFY_EXPR((ResourceStateFlagsToVkAccessFlags(RequiredState) & RequiredAccessFlags) == RequiredAccessFlags); #endif - const bool IsInRequiredState = pBufferVk->CheckState(RequiredState); if (VerifyOnly) { - if (!IsInRequiredState) + if (!pBufferVk->CheckState(RequiredState)) { LOG_ERROR_MESSAGE("State of buffer '", pBufferVk->GetDesc().Name, "' is incorrect. Required state: ", GetResourceStateString(RequiredState), ". Actual state: ", @@ -227,12 +222,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) } else { - // When both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier - // to make sure that all UAV writes are complete and visible. - if (!IsInRequiredState || RequiredState == RESOURCE_STATE_UNORDERED_ACCESS) - { - pCtxVkImpl->TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } + pCtxVkImpl->TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); VERIFY_EXPR(pBufferVk->CheckAccessFlags(RequiredAccessFlags)); } } @@ -275,11 +265,10 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) VERIFY_EXPR(ResourceStateToVkImageLayout(RequiredState) == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } } - const bool IsInRequiredState = pTextureVk->CheckState(RequiredState); if (VerifyOnly) { - if (!IsInRequiredState) + if (!pTextureVk->CheckState(RequiredState)) { LOG_ERROR_MESSAGE("State of texture '", pTextureVk->GetDesc().Name, "' is incorrect. Required state: ", GetResourceStateString(RequiredState), ". Actual state: ", @@ -291,12 +280,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) } else { - // When both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier - // to make sure that all UAV writes are complete and visible. - if (!IsInRequiredState || RequiredState == RESOURCE_STATE_UNORDERED_ACCESS) - { - pCtxVkImpl->TransitionTextureState(*pTextureVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } + pCtxVkImpl->TransitionTextureState(*pTextureVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); } } } @@ -327,11 +311,10 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) auto* pTLASVk = Res.pObject.RawPtr(); if (pTLASVk != nullptr && pTLASVk->IsInKnownState()) { - constexpr RESOURCE_STATE RequiredState = RESOURCE_STATE_RAY_TRACING; - const bool IsInRequiredState = pTLASVk->CheckState(RequiredState); + constexpr RESOURCE_STATE RequiredState = RESOURCE_STATE_RAY_TRACING; if (VerifyOnly) { - if (!IsInRequiredState) + if (!pTLASVk->CheckState(RequiredState)) { LOG_ERROR_MESSAGE("State of TLAS '", pTLASVk->GetDesc().Name, "' is incorrect. Required state: ", GetResourceStateString(RequiredState), ". Actual state: ", @@ -340,13 +323,12 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state " "with IDeviceContext::TransitionResourceStates()."); } + + pTLASVk->CheckBLASVersion(); } else { - if (!IsInRequiredState) - { - pCtxVkImpl->TransitionTLASState(*pTLASVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } + pCtxVkImpl->TransitionTLASState(*pTLASVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); } } } diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp index 143042b8..e039311b 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp @@ -1613,12 +1613,10 @@ VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureF "Please update the switch below to handle the new ray tracing build flag"); VkBuildAccelerationStructureFlagsKHR Result = 0; - for (Uint32 Bit = 1; Bit <= Flags; Bit <<= 1) + while (Flags != RAYTRACING_BUILD_AS_NONE) { - if ((Flags & Bit) != Bit) - continue; - - switch (static_cast(Bit)) + auto FlagBit = static_cast(1 << PlatformMisc::GetLSB(Uint32{Flags})); + switch (FlagBit) { // clang-format off case RAYTRACING_BUILD_AS_ALLOW_UPDATE: Result |= VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; break; @@ -1629,6 +1627,7 @@ VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureF // clang-format on default: UNEXPECTED("unknown build AS flag"); } + Flags = Flags & ~FlagBit; } return Result; } @@ -1639,12 +1638,10 @@ VkGeometryFlagsKHR GeometryFlagsToVkGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flag "Please update the switch below to handle the new ray tracing geometry flag"); VkGeometryFlagsKHR Result = 0; - for (Uint32 Bit = 1; Bit <= Flags; Bit <<= 1) + while (Flags != RAYTRACING_GEOMETRY_NONE) { - if ((Flags & Bit) != Bit) - continue; - - switch (static_cast(Bit)) + auto FlagBit = static_cast(1 << PlatformMisc::GetLSB(Uint32{Flags})); + switch (FlagBit) { // clang-format off case RAYTRACING_GEOMETRY_OPAQUE: Result |= VK_GEOMETRY_OPAQUE_BIT_KHR; break; @@ -1652,6 +1649,7 @@ VkGeometryFlagsKHR GeometryFlagsToVkGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flag // clang-format on default: UNEXPECTED("unknown geometry flag"); } + Flags = Flags & ~FlagBit; } return Result; } @@ -1662,12 +1660,10 @@ VkGeometryInstanceFlagsKHR InstanceFlagsToVkGeometryInstanceFlags(RAYTRACING_INS "Please update the switch below to handle the new ray tracing instance flag"); VkGeometryInstanceFlagsKHR Result = 0; - for (Uint32 Bit = 1; Bit <= Flags; Bit <<= 1) + while (Flags != RAYTRACING_INSTANCE_NONE) { - if ((Flags & Bit) != Bit) - continue; - - switch (static_cast(Bit)) + auto FlagBit = static_cast(1 << PlatformMisc::GetLSB(Uint32{Flags})); + switch (FlagBit) { // clang-format off case RAYTRACING_INSTANCE_TRIANGLE_FACING_CULL_DISABLE: Result |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; break; @@ -1677,6 +1673,7 @@ VkGeometryInstanceFlagsKHR InstanceFlagsToVkGeometryInstanceFlags(RAYTRACING_INS // clang-format on default: UNEXPECTED("unknown instance flag"); } + Flags = Flags & ~FlagBit; } return Result; } @@ -1693,7 +1690,7 @@ VkCopyAccelerationStructureModeKHR CopyASModeToVkCopyAccelerationStructureMode(C // clang-format on default: UNEXPECTED("unknown AS copy mode"); - return static_cast(0); + return VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR; } } diff --git a/Tests/DiligentCoreAPITest/include/InlineShaders/RayTracingTestGLSL.h b/Tests/DiligentCoreAPITest/include/InlineShaders/RayTracingTestGLSL.h index fe761719..7567e526 100644 --- a/Tests/DiligentCoreAPITest/include/InlineShaders/RayTracingTestGLSL.h +++ b/Tests/DiligentCoreAPITest/include/InlineShaders/RayTracingTestGLSL.h @@ -55,7 +55,7 @@ void main() gl_RayFlagsNoneEXT, // rayFlags 0xFF, // cullMask 0, // sbtRecordOffset - 0, // sbtRecordStride + 1, // sbtRecordStride 0, // missIndex origin, // ray origin 0.01, // ray min range @@ -122,7 +122,7 @@ void main() gl_RayFlagsSkipClosestHitShaderEXT, 0xFF, // cullMask 0, // sbtRecordOffset - 0, // sbtRecordStride + 1, // sbtRecordStride 0, // missIndex origin, // ray origin 0.01, // ray min range @@ -207,7 +207,7 @@ void main() gl_RayFlagsNoneEXT, // rayFlags 0xFF, // cullMask 0, // sbtRecordOffset - 0, // sbtRecordStride + 1, // sbtRecordStride 0, // missIndex origin, // ray origin 0.01, // ray min range @@ -280,6 +280,120 @@ void main() // clang-format on +// clang-format off +const std::string RayTracingTest4_RG{ +R"glsl( +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(set=0, binding=0) uniform accelerationStructureEXT g_TLAS; +layout(set=0, binding=1, rgba8) uniform image2D g_ColorBuffer; + +layout(location=0) rayPayloadEXT vec4 payload; + +void main() +{ + const vec2 uv = vec2(gl_LaunchIDEXT.xy) / vec2(gl_LaunchSizeEXT.xy - 1); + const vec3 origin = vec3(uv.x, 1.0 - uv.y, -1.0); + const vec3 direction = vec3(0.0, 0.0, 1.0); + + payload = vec4(0.0); + traceRayEXT(g_TLAS, // acceleration structure + gl_RayFlagsNoneEXT, // rayFlags + 0xFF, // cullMask + 0, // sbtRecordOffset + 1, // sbtRecordStride + 0, // missIndex + origin, // ray origin + 0.01, // ray min range + direction, // ray direction + 10.0, // ray max range + 0); // payload location + + imageStore(g_ColorBuffer, ivec2(gl_LaunchIDEXT), payload); +} +)glsl" +}; + +const std::string RayTracingTest4_RM{ +R"glsl( +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(location=0) rayPayloadInEXT vec4 payload; + +void main() +{ + payload = vec4(0.0, 0.0, 0.2, 1.0); +} +)glsl" +}; + +const std::string RayTracingTest4_Uniforms{ +R"glsl( +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(shaderRecordEXT) buffer ShaderRecord +{ + vec4 Weights; +}; + +layout(location=0) rayPayloadInEXT vec4 payload; +hitAttributeEXT vec2 hitAttribs; + +layout(set=0, binding=2, std430) readonly buffer PerInstanceData { + uint PrimitiveOffsets[3]; +} g_PerInstance[2]; + +layout(set=0, binding=3, std430) readonly buffer PrimitiveData { + uvec4 g_Primitives[9]; +}; + +struct Vertex +{ + vec4 Pos; + vec4 Color1; + vec4 Color2; +}; +layout(set=0, binding=4, std430) readonly buffer VertexData { + Vertex g_Vertices[16]; +}; +)glsl" +}; + +const std::string RayTracingTest4_RCH1 = RayTracingTest4_Uniforms + +R"glsl( +void main() +{ + vec3 barycentrics = vec3(1.0f - hitAttribs.x - hitAttribs.y, hitAttribs.x, hitAttribs.y);// * Weights.xyz; + uint primOffset = g_PerInstance[gl_InstanceID].PrimitiveOffsets[gl_GeometryIndexEXT]; + uvec4 triFace = g_Primitives[primOffset + gl_PrimitiveID]; + Vertex v0 = g_Vertices[triFace.x]; + Vertex v1 = g_Vertices[triFace.y]; + Vertex v2 = g_Vertices[triFace.z]; + vec4 col = v0.Color2 * barycentrics.x + v1.Color2 * barycentrics.y + v2.Color2 * barycentrics.z; + payload = col; +} +)glsl"; + +const std::string RayTracingTest4_RCH2 = RayTracingTest4_Uniforms + +R"glsl( +void main() +{ + vec3 barycentrics = vec3(1.0f - hitAttribs.x - hitAttribs.y, hitAttribs.x, hitAttribs.y);// * Weights.xyz; + uint primOffset = g_PerInstance[gl_InstanceID].PrimitiveOffsets[gl_GeometryIndexEXT]; + uvec4 triFace = g_Primitives[primOffset + gl_PrimitiveID]; + Vertex v0 = g_Vertices[triFace.x]; + Vertex v1 = g_Vertices[triFace.y]; + Vertex v2 = g_Vertices[triFace.z]; + vec4 col = v0.Color1 * barycentrics.x + v1.Color1 * barycentrics.y + v2.Color1 * barycentrics.z; + payload = col; +} +)glsl"; +// clang-format on + + } // namespace GLSL } // namespace diff --git a/Tests/DiligentCoreAPITest/include/InlineShaders/RayTracingTestHLSL.h b/Tests/DiligentCoreAPITest/include/InlineShaders/RayTracingTestHLSL.h index ed64b700..c6b97b6e 100644 --- a/Tests/DiligentCoreAPITest/include/InlineShaders/RayTracingTestHLSL.h +++ b/Tests/DiligentCoreAPITest/include/InlineShaders/RayTracingTestHLSL.h @@ -86,7 +86,7 @@ R"hlsl( [shader("closesthit")] void main(inout RTPayload payload, in BuiltInTriangleIntersectionAttributes attr) { - float3 barycentrics = float3(1 - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, attr.barycentrics.y); + float3 barycentrics = float3(1.0 - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, attr.barycentrics.y); payload.Color = float4(barycentrics, 1.0); } )hlsl"; @@ -147,7 +147,7 @@ R"hlsl( [shader("anyhit")] void main(inout RTPayload payload, in BuiltInTriangleIntersectionAttributes attr) { - float3 barycentrics = float3(1 - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, attr.barycentrics.y); + float3 barycentrics = float3(1.0 - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, attr.barycentrics.y); if (barycentrics.y > barycentrics.x) IgnoreHit(); else @@ -241,6 +241,101 @@ void main() )hlsl"; // clang-format on + +// clang-format off +const std::string RayTracingTest4_RG = RayTracingTest_Payload + +R"hlsl( +RaytracingAccelerationStructure g_TLAS : register(t0); +RWTexture2D g_ColorBuffer : register(u0); + +[shader("raygeneration")] +void main() +{ + const float2 uv = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy - 1); + + RayDesc ray; + ray.Origin = float3(uv.x, 1.0 - uv.y, -1.0); + ray.Direction = float3(0.0, 0.0, 1.0); + ray.TMin = 0.01; + ray.TMax = 10.0; + + RTPayload payload = {float4(0, 0, 0, 0)}; + TraceRay(g_TLAS, // Acceleration Structure + RAY_FLAG_NONE, // Ray Flags + ~0, // Instance Inclusion Mask + 0, // Ray Contribution To Hit Group Index + 1, // Multiplier For Geometry Contribution To Hit Group Index + 0, // Miss Shader Index + ray, + payload); + + g_ColorBuffer[DispatchRaysIndex().xy] = payload.Color; +} +)hlsl"; + +const std::string RayTracingTest4_RM = RayTracingTest_Payload + +R"hlsl( +[shader("miss")] +void main(inout RTPayload payload) +{ + payload.Color = float4(0.0, 0.0, 0.2, 1.0); +} +)hlsl"; + +const std::string RayTracingTest4_Uniforms = RayTracingTest_Payload + +R"hlsl( +struct Vertex +{ + float4 Pos; + float4 Color1; + float4 Color2; +}; +StructuredBuffer g_Vertices : register(t1); // array size = 16 +StructuredBuffer g_PerInstance[2] : register(t2); // array size = 3 +StructuredBuffer g_Primitives : register(t4); // array size = 9 + +// local root constants +struct LocalRootConst +{ + float4 Weight; +}; +//[[vk::shader_record_ext]] +//ConstantBuffer g_LocalRoot : register(b0); +)hlsl"; + +const std::string RayTracingTest4_RCH1 = RayTracingTest4_Uniforms + +R"hlsl( +[shader("closesthit")] +void main(inout RTPayload payload, in BuiltInTriangleIntersectionAttributes attr) +{ + float3 barycentrics = float3(1.0 - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, attr.barycentrics.y);// * g_LocalRoot.Weight.xyz; + uint primOffset = g_PerInstance[InstanceIndex()][GeometryIndex()]; + uint4 triFace = g_Primitives[primOffset + PrimitiveIndex()]; + Vertex v0 = g_Vertices[triFace.x]; + Vertex v1 = g_Vertices[triFace.y]; + Vertex v2 = g_Vertices[triFace.z]; + float4 col = v0.Color2 * barycentrics.x + v1.Color2 * barycentrics.y + v2.Color2 * barycentrics.z; + payload.Color = col; +} +)hlsl"; + +const std::string RayTracingTest4_RCH2 = RayTracingTest4_Uniforms + +R"hlsl( +[shader("closesthit")] +void main(inout RTPayload payload, in BuiltInTriangleIntersectionAttributes attr) +{ + float3 barycentrics = float3(1.0 - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, attr.barycentrics.y);// * g_LocalRoot.Weight.xyz; + uint primOffset = g_PerInstance[InstanceIndex()][GeometryIndex()]; + uint4 triFace = g_Primitives[primOffset + PrimitiveIndex()]; + Vertex v0 = g_Vertices[triFace.x]; + Vertex v1 = g_Vertices[triFace.y]; + Vertex v2 = g_Vertices[triFace.z]; + float4 col = v0.Color1 * barycentrics.x + v1.Color1 * barycentrics.y + v2.Color1 * barycentrics.z; + payload.Color = col; +} +)hlsl"; +// clang-format on + } // namespace HLSL } // namespace diff --git a/Tests/DiligentCoreAPITest/include/RayTracingTestConstants.hpp b/Tests/DiligentCoreAPITest/include/RayTracingTestConstants.hpp new file mode 100644 index 00000000..99ab4bf0 --- /dev/null +++ b/Tests/DiligentCoreAPITest/include/RayTracingTestConstants.hpp @@ -0,0 +1,155 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed 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. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "BasicMath.hpp" + +namespace Diligent +{ + +namespace TestingConstants +{ +// clang-format off + + namespace TriangleClosestHit + { + static const float3 Vertices[] = + { + float3{0.25f, 0.25f, 0.0f}, + float3{0.75f, 0.25f, 0.0f}, + float3{0.50f, 0.75f, 0.0f} + }; + } // namespace TriangleClosestHit + + namespace TriangleAnyHit + { + static const float3 Vertices[] = + { + float3{0.25f, 0.25f, 0.0f}, float3{0.75f, 0.25f, 0.0f}, float3{0.50f, 0.75f, 0.0f}, + float3{0.50f, 0.10f, 0.1f}, float3{0.90f, 0.90f, 0.1f}, float3{0.10f, 0.90f, 0.1f}, + float3{0.40f, 1.00f, 0.2f}, float3{0.20f, 0.40f, 0.2f}, float3{1.00f, 0.70f, 0.2f} + }; + } // namespace TriangleAnyHit + + namespace ProceduralIntersection + { + static const float3 Boxes[] = + { + float3{0.25f, 0.5f, 2.0f} - float3{1.0f, 1.0f, 1.0f}, + float3{0.25f, 0.5f, 2.0f} + float3{1.0f, 1.0f, 1.0f} + }; + } // namespace ProceduralIntersection + + namespace MultiGeometry + { + struct VertexType + { + float4 Pos; + float4 Color1; + float4 Color2; + + VertexType(float2 _Pos, float3 _Color1, float3 _Color2) : + Pos {_Pos.x, _Pos.y, 2.0f, 1.0f}, + Color1{_Color1.x, _Color1.y, _Color1.z, 1.0f}, + Color2{_Color2.x, _Color2.y, _Color2.z, 1.0f} + {} + }; + + static const VertexType Vertices[] = + { + // geometry 1 + VertexType{{0.10f, 0.10f}, {0.7f, 0.3f, 0.1f}, {0.2f, 0.9f, 0.4f}}, // 0 + VertexType{{0.17f, 0.30f}, {0.6f, 0.0f, 0.4f}, {0.2f, 0.5f, 0.8f}}, // 1 + VertexType{{0.10f, 0.31f}, {0.3f, 0.7f, 0.4f}, {0.9f, 0.2f, 0.6f}}, // 2 + VertexType{{0.22f, 0.45f}, {0.2f, 0.9f, 0.7f}, {0.1f, 0.7f, 0.1f}}, // 3 + // geometry 2 + VertexType{{0.27f, 0.10f}, {0.5f, 0.1f, 0.6f}, {0.3f, 0.1f, 0.5f}}, // 4 + VertexType{{0.40f, 0.30f}, {1.0f, 1.0f, 1.0f}, {0.3f, 1.0f, 0.7f}}, // 5 + VertexType{{0.26f, 0.30f}, {0.3f, 0.3f, 0.9f}, {1.0f, 0.0f, 0.3f}}, // 6 + VertexType{{0.40f, 0.47f}, {0.8f, 1.0f, 0.2f}, {1.0f, 0.7f, 0.0f}}, // 7 + VertexType{{0.54f, 0.30f}, {0.1f, 1.0f, 0.9f}, {0.0f, 1.0f, 0.6f}}, // 8 + VertexType{{0.53f, 0.10f}, {1.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f}}, // 9 + // geometry 3 + VertexType{{0.65f, 0.10f}, {0.3f, 0.6f, 0.8f}, {1.0f, 0.9f, 0.2f}}, // 10 + VertexType{{0.63f, 0.25f}, {0.9f, 1.0f, 0.2f}, {0.1f, 0.2f, 0.3f}}, // 11 + VertexType{{0.82f, 0.20f}, {0.4f, 0.5f, 0.0f}, {1.0f, 0.2f, 0.6f}}, // 12 + VertexType{{0.76f, 0.30f}, {1.0f, 0.0f, 0.0f}, {0.4f, 0.7f, 0.2f}}, // 13 + VertexType{{0.55f, 0.48f}, {0.5f, 0.1f, 0.2f}, {1.0f, 0.3f, 0.5f}}, // 14 + VertexType{{0.90f, 0.40f}, {0.8f, 0.2f, 1.0f}, {0.3f, 0.6f, 0.4f}}, // 15 + }; + static const uint Indices[] = + { + 0, 1, 2, 2, 1, 3, // geometry 1 + 4, 5, 6, 6, 7, 8, 8, 5, 9, // geometry 2 + 10, 12, 11, 11, 12, 13, 11, 13, 14, 13, 12, 15, // geometry 3 + }; + static const uint4 Primitives[] = + { + // geometry 1 + {Indices[ 0], Indices[ 1], Indices[ 2], 0}, // 0 + {Indices[ 3], Indices[ 4], Indices[ 5], 0}, // 1 + // geometry 2 + {Indices[ 6], Indices[ 7], Indices[ 8], 0}, // 2 + {Indices[ 9], Indices[10], Indices[11], 0}, // 3 + {Indices[12], Indices[13], Indices[14], 0}, // 4 + // geometry 3 + {Indices[15], Indices[16], Indices[17], 0}, // 5 + {Indices[18], Indices[19], Indices[20], 0}, // 6 + {Indices[21], Indices[22], Indices[23], 0}, // 7 + {Indices[24], Indices[25], Indices[26], 0} // 8 + }; + static const uint PrimitiveOffsets[] = + { + 0, 2, 5 + }; + + struct ShaderRecord + { + float4 Weight; + float4 Padding; + }; + static const ShaderRecord Weights[] = + { + ShaderRecord{{1.0f, 0.4f, 0.4f, 1.0f}, {}}, + ShaderRecord{{0.4f, 1.0f, 0.4f, 1.0f}, {}}, + ShaderRecord{{0.4f, 0.4f, 1.0f, 1.0f}, {}} + }; + static constexpr Uint32 ShaderRecordSize = sizeof(Weights[0]); + static constexpr Uint32 InstanceCount = 2; + + static_assert(_countof(Vertices) == 16, "Update array size in shaders"); + static_assert(_countof(PrimitiveOffsets) == 3, "Update array size in shaders"); + static_assert(_countof(Primitives) == 9, "Update array size in shaders"); + static_assert(_countof(Indices) % 3 == 0, "Invalid index count"); + static_assert(_countof(Indices) / 3 == _countof(Primitives), "Primitive count mismatch"); + + } // namespace MultiGeometry + +// clang-format on + +} // namespace TestingConstants + +} // namespace Diligent diff --git a/Tests/DiligentCoreAPITest/src/D3D12/RayTracingReferenceD3D12.cpp b/Tests/DiligentCoreAPITest/src/D3D12/RayTracingReferenceD3D12.cpp index 79eb6e96..cd709797 100644 --- a/Tests/DiligentCoreAPITest/src/D3D12/RayTracingReferenceD3D12.cpp +++ b/Tests/DiligentCoreAPITest/src/D3D12/RayTracingReferenceD3D12.cpp @@ -34,6 +34,7 @@ #include "BasicMath.hpp" #include "InlineShaders/RayTracingTestHLSL.h" +#include "RayTracingTestConstants.hpp" namespace Diligent { @@ -46,17 +47,21 @@ namespace struct RTContext { - ID3D12Device5* pDevice = nullptr; + struct AccelStruct + { + CComPtr pAS; + UINT64 BuildScratchSize = 0; + UINT64 UpdateScratchSize = 0; + }; + + CComPtr pDevice; CComPtr pCmdList; CComPtr pRayTracingSO; CComPtr pStateObjectProperties; - CComPtr pRootSignature; - CComPtr pBLAS; - UINT64 BLASBuildScratchSize = 0; - UINT64 BLASUpdateScratchSize = 0; - CComPtr pTLAS; - UINT64 TLASBuildScratchSize = 0; - UINT64 TLASUpdateScratchSize = 0; + CComPtr pGlobalRootSignature; + CComPtr pLocalRootSignature; + AccelStruct BLAS; + AccelStruct TLAS; CComPtr pScratchBuffer; CComPtr pVertexBuffer; CComPtr pIndexBuffer; @@ -96,8 +101,8 @@ struct RTContext static constexpr UINT DescriptorHeapSize = 16; }; -template -void InitializeRTContext(RTContext& Ctx, ISwapChain* pSwapChain, PSOCtorType&& PSOCtor) +template +void InitializeRTContext(RTContext& Ctx, ISwapChain* pSwapChain, Uint32 ShaderRecordSize, PSOCtorType&& PSOCtor, RootSigCtorType&& RootSigCtor) { auto* pEnv = TestingEnvironmentD3D12::GetInstance(); auto* pTestingSwapChainD3D12 = ValidatedCast(pSwapChain); @@ -110,38 +115,90 @@ void InitializeRTContext(RTContext& Ctx, ISwapChain* pSwapChain, PSOCtorType&& P hr = pEnv->CreateGraphicsCommandList()->QueryInterface(IID_PPV_ARGS(&Ctx.pCmdList)); ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to get ID3D12GraphicsCommandList4"; - // create root signature + // create descriptor heap + { + D3D12_DESCRIPTOR_HEAP_DESC Desc = {}; + + Desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + Desc.NumDescriptors = Ctx.DescriptorHeapSize; + Desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + Desc.NodeMask = 0; + + hr = Ctx.pDevice->CreateDescriptorHeap(&Desc, IID_PPV_ARGS(&Ctx.pDescHeap)); + ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to create descriptor heap"; + + Ctx.DescHeapCount = 0; + Ctx.DescHandleSize = Ctx.pDevice->GetDescriptorHandleIncrementSize(Desc.Type); + + D3D12_UNORDERED_ACCESS_VIEW_DESC UAVDesc = {}; + + UAVDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + UAVDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; + + D3D12_CPU_DESCRIPTOR_HANDLE UAVHandle = Ctx.pDescHeap->GetCPUDescriptorHandleForHeapStart(); + ASSERT_LT(Ctx.DescHeapCount, Ctx.DescriptorHeapSize); + ASSERT_TRUE(Ctx.DescHeapCount == 0); + UAVHandle.ptr += Ctx.DescHandleSize * Ctx.DescHeapCount++; + Ctx.pDevice->CreateUnorderedAccessView(pTestingSwapChainD3D12->GetD3D12RenderTarget(), nullptr, &UAVDesc, UAVHandle); + } + + // create global root signature { - D3D12_ROOT_SIGNATURE_DESC RootSignatureDesc = {}; - D3D12_DESCRIPTOR_RANGE DescriptorRanges[2] = {}; - D3D12_ROOT_PARAMETER Params[1] = {}; - - DescriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - DescriptorRanges[0].NumDescriptors = 1; - DescriptorRanges[0].BaseShaderRegister = 0; - DescriptorRanges[0].RegisterSpace = 0; - DescriptorRanges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - - DescriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - DescriptorRanges[1].NumDescriptors = 1; - DescriptorRanges[1].BaseShaderRegister = 0; - DescriptorRanges[1].RegisterSpace = 0; - DescriptorRanges[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - - Params[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - Params[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - Params[0].DescriptorTable.NumDescriptorRanges = _countof(DescriptorRanges); - Params[0].DescriptorTable.pDescriptorRanges = DescriptorRanges; + D3D12_ROOT_SIGNATURE_DESC RootSignatureDesc = {}; + D3D12_ROOT_PARAMETER Param = {}; + D3D12_DESCRIPTOR_RANGE Range = {}; + std::vector DescriptorRanges; + + RootSigCtor(DescriptorRanges); + + Range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + Range.NumDescriptors = 1; + Range.OffsetInDescriptorsFromTableStart = 0; + DescriptorRanges.push_back(Range); // g_TLAS + + Range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + Range.NumDescriptors = 1; + Range.OffsetInDescriptorsFromTableStart = 1; + DescriptorRanges.push_back(Range); // g_ColorBuffer + + Param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + Param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + Param.DescriptorTable.NumDescriptorRanges = static_cast(DescriptorRanges.size()); + Param.DescriptorTable.pDescriptorRanges = DescriptorRanges.data(); RootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; - RootSignatureDesc.NumParameters = _countof(Params); - RootSignatureDesc.pParameters = Params; + RootSignatureDesc.NumParameters = 1; + RootSignatureDesc.pParameters = &Param; + + CComPtr signature; + hr = D3D12SerializeRootSignature(&RootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr); + ASSERT_HRESULT_SUCCEEDED(hr); + + hr = Ctx.pDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&Ctx.pGlobalRootSignature)); + ASSERT_HRESULT_SUCCEEDED(hr); + } + + // create local root signature + if (ShaderRecordSize > 0) + { + D3D12_ROOT_SIGNATURE_DESC RootSignatureDesc = {}; + D3D12_ROOT_PARAMETER Param = {}; + + Param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + Param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + Param.Constants.Num32BitValues = ShaderRecordSize / 4; + Param.Constants.RegisterSpace = 1; + Param.Constants.ShaderRegister = 0; + + RootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; + RootSignatureDesc.NumParameters = 1; + RootSignatureDesc.pParameters = &Param; CComPtr signature; hr = D3D12SerializeRootSignature(&RootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr); ASSERT_HRESULT_SUCCEEDED(hr); - hr = Ctx.pDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&Ctx.pRootSignature)); + hr = Ctx.pDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&Ctx.pLocalRootSignature)); ASSERT_HRESULT_SUCCEEDED(hr); } @@ -165,9 +222,14 @@ void InitializeRTContext(RTContext& Ctx, ISwapChain* pSwapChain, PSOCtorType&& P Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG, &ShaderConfig}); D3D12_GLOBAL_ROOT_SIGNATURE GlobalRoot; - GlobalRoot.pGlobalRootSignature = Ctx.pRootSignature; + GlobalRoot.pGlobalRootSignature = Ctx.pGlobalRootSignature; Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE, &GlobalRoot}); + D3D12_LOCAL_ROOT_SIGNATURE LocalRoot; + LocalRoot.pLocalRootSignature = Ctx.pLocalRootSignature; + if (Ctx.pLocalRootSignature) + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE, &LocalRoot}); + D3D12_STATE_OBJECT_DESC RTPipelineDesc; RTPipelineDesc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; RTPipelineDesc.NumSubobjects = static_cast(Subobjects.size()); @@ -179,32 +241,12 @@ void InitializeRTContext(RTContext& Ctx, ISwapChain* pSwapChain, PSOCtorType&& P hr = Ctx.pRayTracingSO->QueryInterface(IID_PPV_ARGS(&Ctx.pStateObjectProperties)); ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to get state object properties"; } +} - // create descriptor heap - { - D3D12_DESCRIPTOR_HEAP_DESC Desc = {}; - - Desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - Desc.NumDescriptors = Ctx.DescriptorHeapSize; - Desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - Desc.NodeMask = 0; - - hr = Ctx.pDevice->CreateDescriptorHeap(&Desc, IID_PPV_ARGS(&Ctx.pDescHeap)); - ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to create descriptor heap"; - - Ctx.DescHeapCount = 0; - Ctx.DescHandleSize = Ctx.pDevice->GetDescriptorHandleIncrementSize(Desc.Type); - - D3D12_UNORDERED_ACCESS_VIEW_DESC UAVDesc = {}; - - UAVDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - UAVDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; - - D3D12_CPU_DESCRIPTOR_HANDLE UAVHandle = Ctx.pDescHeap->GetCPUDescriptorHandleForHeapStart(); - ASSERT_LT(Ctx.DescHeapCount, Ctx.DescriptorHeapSize); - UAVHandle.ptr += Ctx.DescHandleSize * Ctx.DescHeapCount++; - Ctx.pDevice->CreateUnorderedAccessView(pTestingSwapChainD3D12->GetD3D12RenderTarget(), nullptr, &UAVDesc, UAVHandle); - } +template +void InitializeRTContext(RTContext& Ctx, ISwapChain* pSwapChain, Uint32 ShaderRecordSize, PSOCtorType&& PSOCtor) +{ + InitializeRTContext(Ctx, pSwapChain, ShaderRecordSize, PSOCtor, [](std::vector&) {}); } void CreateBLAS(RTContext& Ctx, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& BottomLevelInputs) @@ -240,11 +282,11 @@ void CreateBLAS(RTContext& Ctx, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_IN auto hr = Ctx.pDevice->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, &ASDesc, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, nullptr, - IID_PPV_ARGS(&Ctx.pBLAS)); + IID_PPV_ARGS(&Ctx.BLAS.pAS)); ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to create acceleration structure"; - Ctx.BLASBuildScratchSize = BottomLevelPrebuildInfo.ScratchDataSizeInBytes; - Ctx.BLASUpdateScratchSize = BottomLevelPrebuildInfo.UpdateScratchDataSizeInBytes; + Ctx.BLAS.BuildScratchSize = BottomLevelPrebuildInfo.ScratchDataSizeInBytes; + Ctx.BLAS.UpdateScratchSize = BottomLevelPrebuildInfo.UpdateScratchDataSizeInBytes; } void CreateTLAS(RTContext& Ctx, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& TopLevelInputs) @@ -280,26 +322,27 @@ void CreateTLAS(RTContext& Ctx, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_IN auto hr = Ctx.pDevice->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, &ASDesc, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, nullptr, - IID_PPV_ARGS(&Ctx.pTLAS)); + IID_PPV_ARGS(&Ctx.TLAS.pAS)); ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to create acceleration structure"; - Ctx.TLASBuildScratchSize = TopLevelPrebuildInfo.ScratchDataSizeInBytes; - Ctx.TLASUpdateScratchSize = TopLevelPrebuildInfo.UpdateScratchDataSizeInBytes; + Ctx.TLAS.BuildScratchSize = TopLevelPrebuildInfo.ScratchDataSizeInBytes; + Ctx.TLAS.UpdateScratchSize = TopLevelPrebuildInfo.UpdateScratchDataSizeInBytes; D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {}; SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; SRVDesc.Format = DXGI_FORMAT_UNKNOWN; - SRVDesc.RaytracingAccelerationStructure.Location = Ctx.pTLAS->GetGPUVirtualAddress(); + SRVDesc.RaytracingAccelerationStructure.Location = Ctx.TLAS.pAS->GetGPUVirtualAddress(); D3D12_CPU_DESCRIPTOR_HANDLE DescHandle = Ctx.pDescHeap->GetCPUDescriptorHandleForHeapStart(); ASSERT_LT(Ctx.DescHeapCount, Ctx.DescriptorHeapSize); + ASSERT_TRUE(Ctx.DescHeapCount == 1); DescHandle.ptr += Ctx.DescHandleSize * Ctx.DescHeapCount++; Ctx.pDevice->CreateShaderResourceView(nullptr, &SRVDesc, DescHandle); } -void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 InstanceCount, Uint32 NumMissShaders, Uint32 NumHitShaders) +void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 InstanceCount, Uint32 NumMissShaders, Uint32 NumHitShaders, Uint32 ShaderRecordSize = 0, size_t UploadSize = 0) { D3D12_RESOURCE_DESC BuffDesc = {}; BuffDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; @@ -320,17 +363,15 @@ void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 Instan HeapProps.CreationNodeMask = 1; HeapProps.VisibleNodeMask = 1; - BuffDesc.Width = std::max(Ctx.BLASBuildScratchSize, Ctx.BLASUpdateScratchSize); - BuffDesc.Width = std::max(BuffDesc.Width, Ctx.TLASBuildScratchSize); - BuffDesc.Width = std::max(BuffDesc.Width, Ctx.TLASUpdateScratchSize); + BuffDesc.Width = std::max(Ctx.BLAS.BuildScratchSize, Ctx.BLAS.UpdateScratchSize); + BuffDesc.Width = std::max(BuffDesc.Width, Ctx.TLAS.BuildScratchSize); + BuffDesc.Width = std::max(BuffDesc.Width, Ctx.TLAS.UpdateScratchSize); auto hr = Ctx.pDevice->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, &BuffDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&Ctx.pScratchBuffer)); ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to create buffer"; - size_t UploadSize = 0; - if (VBSize > 0) { BuffDesc.Width = VBSize; @@ -366,12 +407,12 @@ void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 Instan // SBT { - const UINT64 handleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + const UINT64 RecordSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES + ShaderRecordSize; const UINT64 align = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; - BuffDesc.Width = Align(handleSize, align); - BuffDesc.Width = Align(BuffDesc.Width + NumMissShaders * handleSize, align); - BuffDesc.Width = Align(BuffDesc.Width + NumHitShaders * handleSize, align); + BuffDesc.Width = Align(RecordSize, align); + BuffDesc.Width = Align(BuffDesc.Width + NumMissShaders * RecordSize, align); + BuffDesc.Width = Align(BuffDesc.Width + NumHitShaders * RecordSize, align); hr = Ctx.pDevice->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, &BuffDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, @@ -420,7 +461,7 @@ void RayTracingTriangleClosestHitReferenceD3D12(ISwapChain* pSwapChain) const auto& SCDesc = pSwapChain->GetDesc(); RTContext Ctx = {}; - InitializeRTContext(Ctx, pSwapChain, + InitializeRTContext(Ctx, pSwapChain, 0, [pEnv](auto& Subobjects, auto& ExportDescs, auto& LibDescs, auto& HitGroups, auto& ShadersByteCode) { ShadersByteCode.resize(3); ExportDescs.resize(ShadersByteCode.size()); @@ -487,12 +528,7 @@ void RayTracingTriangleClosestHitReferenceD3D12(ISwapChain* pSwapChain) D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& TopLevelInputs = TLASDesc.Inputs; D3D12_RAYTRACING_INSTANCE_DESC Instance = {}; - const float3 Vertices[] = // - { - float3{0.25f, 0.25f, 0.0f}, - float3{0.75f, 0.25f, 0.0f}, - float3{0.50f, 0.75f, 0.0f} // - }; + const auto& Vertices = TestingConstants::TriangleClosestHit::Vertices; Geometry.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; Geometry.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; @@ -518,7 +554,7 @@ void RayTracingTriangleClosestHitReferenceD3D12(ISwapChain* pSwapChain) Instance.InstanceContributionToHitGroupIndex = 0; Instance.InstanceMask = 0xFF; Instance.Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE; - Instance.AccelerationStructure = Ctx.pBLAS->GetGPUVirtualAddress(); + Instance.AccelerationStructure = Ctx.BLAS.pAS->GetGPUVirtualAddress(); Instance.Transform[0][0] = 1.0f; Instance.Transform[1][1] = 1.0f; Instance.Transform[2][2] = 1.0f; @@ -557,7 +593,7 @@ void RayTracingTriangleClosestHitReferenceD3D12(ISwapChain* pSwapChain) Geometry.Triangles.VertexBuffer.StartAddress = Ctx.pVertexBuffer->GetGPUVirtualAddress(); - BLASDesc.DestAccelerationStructureData = Ctx.pBLAS->GetGPUVirtualAddress(); + BLASDesc.DestAccelerationStructureData = Ctx.BLAS.pAS->GetGPUVirtualAddress(); BLASDesc.ScratchAccelerationStructureData = Ctx.pScratchBuffer->GetGPUVirtualAddress(); BLASDesc.SourceAccelerationStructureData = 0; @@ -579,7 +615,7 @@ void RayTracingTriangleClosestHitReferenceD3D12(ISwapChain* pSwapChain) TopLevelInputs.InstanceDescs = Ctx.pInstanceBuffer->GetGPUVirtualAddress(); - TLASDesc.DestAccelerationStructureData = Ctx.pTLAS->GetGPUVirtualAddress(); + TLASDesc.DestAccelerationStructureData = Ctx.TLAS.pAS->GetGPUVirtualAddress(); TLASDesc.ScratchAccelerationStructureData = Ctx.pScratchBuffer->GetGPUVirtualAddress(); TLASDesc.SourceAccelerationStructureData = 0; @@ -598,7 +634,7 @@ void RayTracingTriangleClosestHitReferenceD3D12(ISwapChain* pSwapChain) ID3D12DescriptorHeap* DescHeaps[] = {Ctx.pDescHeap}; Ctx.pCmdList->SetPipelineState1(Ctx.pRayTracingSO); - Ctx.pCmdList->SetComputeRootSignature(Ctx.pRootSignature); + Ctx.pCmdList->SetComputeRootSignature(Ctx.pGlobalRootSignature); Ctx.pCmdList->SetDescriptorHeaps(_countof(DescHeaps), &DescHeaps[0]); Ctx.pCmdList->SetComputeRootDescriptorTable(0, DescHeaps[0]->GetGPUDescriptorHandleForHeapStart()); @@ -657,7 +693,7 @@ void RayTracingTriangleAnyHitReferenceD3D12(ISwapChain* pSwapChain) const auto& SCDesc = pSwapChain->GetDesc(); RTContext Ctx = {}; - InitializeRTContext(Ctx, pSwapChain, + InitializeRTContext(Ctx, pSwapChain, 0, [pEnv](auto& Subobjects, auto& ExportDescs, auto& LibDescs, auto& HitGroups, auto& ShadersByteCode) { ShadersByteCode.resize(4); ExportDescs.resize(ShadersByteCode.size()); @@ -738,12 +774,7 @@ void RayTracingTriangleAnyHitReferenceD3D12(ISwapChain* pSwapChain) D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& TopLevelInputs = TLASDesc.Inputs; D3D12_RAYTRACING_INSTANCE_DESC Instance = {}; - const float3 Vertices[] = // - { - float3{0.25f, 0.25f, 0.0f}, float3{0.75f, 0.25f, 0.0f}, float3{0.50f, 0.75f, 0.0f}, - float3{0.50f, 0.10f, 0.1f}, float3{0.90f, 0.90f, 0.1f}, float3{0.10f, 0.90f, 0.1f}, - float3{0.40f, 1.00f, 0.2f}, float3{0.20f, 0.40f, 0.2f}, float3{1.00f, 0.70f, 0.2f} // - }; + const auto& Vertices = TestingConstants::TriangleAnyHit::Vertices; Geometry.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; Geometry.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; @@ -769,7 +800,7 @@ void RayTracingTriangleAnyHitReferenceD3D12(ISwapChain* pSwapChain) Instance.InstanceContributionToHitGroupIndex = 0; Instance.InstanceMask = 0xFF; Instance.Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE; - Instance.AccelerationStructure = Ctx.pBLAS->GetGPUVirtualAddress(); + Instance.AccelerationStructure = Ctx.BLAS.pAS->GetGPUVirtualAddress(); Instance.Transform[0][0] = 1.0f; Instance.Transform[1][1] = 1.0f; Instance.Transform[2][2] = 1.0f; @@ -808,7 +839,7 @@ void RayTracingTriangleAnyHitReferenceD3D12(ISwapChain* pSwapChain) Geometry.Triangles.VertexBuffer.StartAddress = Ctx.pVertexBuffer->GetGPUVirtualAddress(); - BLASDesc.DestAccelerationStructureData = Ctx.pBLAS->GetGPUVirtualAddress(); + BLASDesc.DestAccelerationStructureData = Ctx.BLAS.pAS->GetGPUVirtualAddress(); BLASDesc.ScratchAccelerationStructureData = Ctx.pScratchBuffer->GetGPUVirtualAddress(); BLASDesc.SourceAccelerationStructureData = 0; @@ -830,7 +861,7 @@ void RayTracingTriangleAnyHitReferenceD3D12(ISwapChain* pSwapChain) TopLevelInputs.InstanceDescs = Ctx.pInstanceBuffer->GetGPUVirtualAddress(); - TLASDesc.DestAccelerationStructureData = Ctx.pTLAS->GetGPUVirtualAddress(); + TLASDesc.DestAccelerationStructureData = Ctx.TLAS.pAS->GetGPUVirtualAddress(); TLASDesc.ScratchAccelerationStructureData = Ctx.pScratchBuffer->GetGPUVirtualAddress(); TLASDesc.SourceAccelerationStructureData = 0; @@ -849,7 +880,7 @@ void RayTracingTriangleAnyHitReferenceD3D12(ISwapChain* pSwapChain) ID3D12DescriptorHeap* DescHeaps[] = {Ctx.pDescHeap}; Ctx.pCmdList->SetPipelineState1(Ctx.pRayTracingSO); - Ctx.pCmdList->SetComputeRootSignature(Ctx.pRootSignature); + Ctx.pCmdList->SetComputeRootSignature(Ctx.pGlobalRootSignature); Ctx.pCmdList->SetDescriptorHeaps(_countof(DescHeaps), &DescHeaps[0]); Ctx.pCmdList->SetComputeRootDescriptorTable(0, DescHeaps[0]->GetGPUDescriptorHandleForHeapStart()); @@ -908,7 +939,7 @@ void RayTracingProceduralIntersectionReferenceD3D12(ISwapChain* pSwapChain) const auto& SCDesc = pSwapChain->GetDesc(); RTContext Ctx = {}; - InitializeRTContext(Ctx, pSwapChain, + InitializeRTContext(Ctx, pSwapChain, 0, [pEnv](auto& Subobjects, auto& ExportDescs, auto& LibDescs, auto& HitGroups, auto& ShadersByteCode) { ShadersByteCode.resize(4); ExportDescs.resize(ShadersByteCode.size()); @@ -989,11 +1020,7 @@ void RayTracingProceduralIntersectionReferenceD3D12(ISwapChain* pSwapChain) D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& TopLevelInputs = TLASDesc.Inputs; D3D12_RAYTRACING_INSTANCE_DESC Instance = {}; - const float3 Boxes[] = // - { - float3{0.25f, 0.5f, 2.0f} - float3{1.0f, 1.0f, 1.0f}, - float3{0.25f, 0.5f, 2.0f} + float3{1.0f, 1.0f, 1.0f} // - }; + const auto& Boxes = TestingConstants::ProceduralIntersection::Boxes; Geometry.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; Geometry.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; @@ -1014,7 +1041,7 @@ void RayTracingProceduralIntersectionReferenceD3D12(ISwapChain* pSwapChain) Instance.InstanceContributionToHitGroupIndex = 0; Instance.InstanceMask = 0xFF; Instance.Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE; - Instance.AccelerationStructure = Ctx.pBLAS->GetGPUVirtualAddress(); + Instance.AccelerationStructure = Ctx.BLAS.pAS->GetGPUVirtualAddress(); Instance.Transform[0][0] = 1.0f; Instance.Transform[1][1] = 1.0f; Instance.Transform[2][2] = 1.0f; @@ -1053,7 +1080,7 @@ void RayTracingProceduralIntersectionReferenceD3D12(ISwapChain* pSwapChain) Geometry.AABBs.AABBs.StartAddress = Ctx.pVertexBuffer->GetGPUVirtualAddress(); - BLASDesc.DestAccelerationStructureData = Ctx.pBLAS->GetGPUVirtualAddress(); + BLASDesc.DestAccelerationStructureData = Ctx.BLAS.pAS->GetGPUVirtualAddress(); BLASDesc.ScratchAccelerationStructureData = Ctx.pScratchBuffer->GetGPUVirtualAddress(); BLASDesc.SourceAccelerationStructureData = 0; @@ -1075,7 +1102,7 @@ void RayTracingProceduralIntersectionReferenceD3D12(ISwapChain* pSwapChain) TopLevelInputs.InstanceDescs = Ctx.pInstanceBuffer->GetGPUVirtualAddress(); - TLASDesc.DestAccelerationStructureData = Ctx.pTLAS->GetGPUVirtualAddress(); + TLASDesc.DestAccelerationStructureData = Ctx.TLAS.pAS->GetGPUVirtualAddress(); TLASDesc.ScratchAccelerationStructureData = Ctx.pScratchBuffer->GetGPUVirtualAddress(); TLASDesc.SourceAccelerationStructureData = 0; @@ -1094,7 +1121,7 @@ void RayTracingProceduralIntersectionReferenceD3D12(ISwapChain* pSwapChain) ID3D12DescriptorHeap* DescHeaps[] = {Ctx.pDescHeap}; Ctx.pCmdList->SetPipelineState1(Ctx.pRayTracingSO); - Ctx.pCmdList->SetComputeRootSignature(Ctx.pRootSignature); + Ctx.pCmdList->SetComputeRootSignature(Ctx.pGlobalRootSignature); Ctx.pCmdList->SetDescriptorHeaps(_countof(DescHeaps), &DescHeaps[0]); Ctx.pCmdList->SetComputeRootDescriptorTable(0, DescHeaps[0]->GetGPUDescriptorHandleForHeapStart()); @@ -1144,6 +1171,440 @@ void RayTracingProceduralIntersectionReferenceD3D12(ISwapChain* pSwapChain) pEnv->ExecuteCommandList(Ctx.pCmdList, true); } + +void RayTracingMultiGeometryReferenceD3D12(ISwapChain* pSwapChain) +{ + static constexpr Uint32 InstanceCount = TestingConstants::MultiGeometry::InstanceCount; + static constexpr Uint32 GeometryCount = 3; + static constexpr Uint32 HitGroupCount = InstanceCount * GeometryCount; + + auto* pEnv = TestingEnvironmentD3D12::GetInstance(); + auto* pTestingSwapChainD3D12 = ValidatedCast(pSwapChain); + + const auto& SCDesc = pSwapChain->GetDesc(); + + RTContext Ctx = {}; + InitializeRTContext( + Ctx, pSwapChain, + TestingConstants::MultiGeometry::ShaderRecordSize, + [pEnv](auto& Subobjects, auto& ExportDescs, auto& LibDescs, auto& HitGroups, auto& ShadersByteCode) { + ShadersByteCode.resize(4); + ExportDescs.resize(ShadersByteCode.size()); + LibDescs.resize(ShadersByteCode.size()); + HitGroups.resize(2); + + auto hr = pEnv->CompileDXILShader(HLSL::RayTracingTest4_RG, L"main", nullptr, 0, L"lib_6_5", &ShadersByteCode[0]); + ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to compile ray gen shader"; + + hr = pEnv->CompileDXILShader(HLSL::RayTracingTest4_RM, L"main", nullptr, 0, L"lib_6_5", &ShadersByteCode[1]); + ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to compile ray miss shader"; + + hr = pEnv->CompileDXILShader(HLSL::RayTracingTest4_RCH1, L"main", nullptr, 0, L"lib_6_5", &ShadersByteCode[2]); + ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to compile ray closest hit shader"; + + hr = pEnv->CompileDXILShader(HLSL::RayTracingTest4_RCH2, L"main", nullptr, 0, L"lib_6_5", &ShadersByteCode[3]); + ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to compile ray closest hit shader"; + + D3D12_EXPORT_DESC& RGExportDesc = ExportDescs[0]; + D3D12_DXIL_LIBRARY_DESC& RGLibDesc = LibDescs[0]; + RGExportDesc.Flags = D3D12_EXPORT_FLAG_NONE; + RGExportDesc.ExportToRename = L"main"; // shader entry name + RGExportDesc.Name = L"Main"; + RGLibDesc.DXILLibrary.BytecodeLength = ShadersByteCode[0]->GetBufferSize(); + RGLibDesc.DXILLibrary.pShaderBytecode = ShadersByteCode[0]->GetBufferPointer(); + RGLibDesc.NumExports = 1; + RGLibDesc.pExports = &RGExportDesc; + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &RGLibDesc}); + + D3D12_EXPORT_DESC& RMExportDesc = ExportDescs[1]; + D3D12_DXIL_LIBRARY_DESC& RMLibDesc = LibDescs[1]; + RMExportDesc.Flags = D3D12_EXPORT_FLAG_NONE; + RMExportDesc.ExportToRename = L"main"; // shader entry name + RMExportDesc.Name = L"Miss"; + RMLibDesc.DXILLibrary.BytecodeLength = ShadersByteCode[1]->GetBufferSize(); + RMLibDesc.DXILLibrary.pShaderBytecode = ShadersByteCode[1]->GetBufferPointer(); + RMLibDesc.NumExports = 1; + RMLibDesc.pExports = &RMExportDesc; + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &RMLibDesc}); + + D3D12_EXPORT_DESC& RCH1ExportDesc = ExportDescs[2]; + D3D12_DXIL_LIBRARY_DESC& RCH1LibDesc = LibDescs[2]; + RCH1ExportDesc.Flags = D3D12_EXPORT_FLAG_NONE; + RCH1ExportDesc.ExportToRename = L"main"; // shader entry name + RCH1ExportDesc.Name = L"ClosestHitShader1"; + RCH1LibDesc.DXILLibrary.BytecodeLength = ShadersByteCode[2]->GetBufferSize(); + RCH1LibDesc.DXILLibrary.pShaderBytecode = ShadersByteCode[2]->GetBufferPointer(); + RCH1LibDesc.NumExports = 1; + RCH1LibDesc.pExports = &RCH1ExportDesc; + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &RCH1LibDesc}); + + D3D12_EXPORT_DESC& RCH2ExportDesc = ExportDescs[3]; + D3D12_DXIL_LIBRARY_DESC& RCH2LibDesc = LibDescs[3]; + RCH2ExportDesc.Flags = D3D12_EXPORT_FLAG_NONE; + RCH2ExportDesc.ExportToRename = L"main"; // shader entry name + RCH2ExportDesc.Name = L"ClosestHitShader2"; + RCH2LibDesc.DXILLibrary.BytecodeLength = ShadersByteCode[3]->GetBufferSize(); + RCH2LibDesc.DXILLibrary.pShaderBytecode = ShadersByteCode[3]->GetBufferPointer(); + RCH2LibDesc.NumExports = 1; + RCH2LibDesc.pExports = &RCH2ExportDesc; + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &RCH2LibDesc}); + + D3D12_HIT_GROUP_DESC& HitGroup1Desc = HitGroups[0]; + HitGroup1Desc.HitGroupExport = L"HitGroup1"; + HitGroup1Desc.Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; + HitGroup1Desc.ClosestHitShaderImport = L"ClosestHitShader1"; + HitGroup1Desc.AnyHitShaderImport = nullptr; + HitGroup1Desc.IntersectionShaderImport = nullptr; + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP, &HitGroup1Desc}); + + D3D12_HIT_GROUP_DESC& HitGroup2Desc = HitGroups[1]; + HitGroup2Desc.HitGroupExport = L"HitGroup2"; + HitGroup2Desc.Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; + HitGroup2Desc.ClosestHitShaderImport = L"ClosestHitShader2"; + HitGroup2Desc.AnyHitShaderImport = nullptr; + HitGroup2Desc.IntersectionShaderImport = nullptr; + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP, &HitGroup2Desc}); + }, + [](std::vector& DescriptorRanges) { + D3D12_DESCRIPTOR_RANGE Range = {}; + Range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + Range.NumDescriptors = 1; + + Range.BaseShaderRegister = 1; + Range.OffsetInDescriptorsFromTableStart = 2; + DescriptorRanges.push_back(Range); // g_Vertices + + Range.BaseShaderRegister = 4; + Range.OffsetInDescriptorsFromTableStart = 3; + DescriptorRanges.push_back(Range); // g_Primitives + + Range.BaseShaderRegister = 2; + Range.NumDescriptors = 2; + Range.OffsetInDescriptorsFromTableStart = 4; + DescriptorRanges.push_back(Range); // g_PerInstance[2] + }); + + const auto& PrimitiveOffsets = TestingConstants::MultiGeometry::PrimitiveOffsets; + const auto& Primitives = TestingConstants::MultiGeometry::Primitives; + const auto& Vertices = TestingConstants::MultiGeometry::Vertices; + + // create acceleration structurea + { + const auto& Indices = TestingConstants::MultiGeometry::Indices; + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BLASDesc = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& BottomLevelInputs = BLASDesc.Inputs; + D3D12_RAYTRACING_GEOMETRY_DESC Geometries[3] = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC TLASDesc = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& TopLevelInputs = TLASDesc.Inputs; + D3D12_RAYTRACING_INSTANCE_DESC Instances[2] = {}; + + static_assert(GeometryCount == _countof(Geometries), "size mismatch"); + static_assert(InstanceCount == _countof(Instances), "size mismatch"); + + Geometries[0].Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + Geometries[0].Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; + Geometries[0].Triangles.VertexBuffer.StartAddress = 0; + Geometries[0].Triangles.VertexBuffer.StrideInBytes = sizeof(Vertices[0]); + Geometries[0].Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; + Geometries[0].Triangles.VertexCount = _countof(Vertices); + Geometries[0].Triangles.IndexCount = PrimitiveOffsets[1] * 3; + Geometries[0].Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; + Geometries[0].Triangles.IndexBuffer = 0; + Geometries[0].Triangles.Transform3x4 = 0; + + Geometries[1].Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + Geometries[1].Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; + Geometries[1].Triangles.VertexBuffer.StartAddress = 0; + Geometries[1].Triangles.VertexBuffer.StrideInBytes = sizeof(Vertices[0]); + Geometries[1].Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; + Geometries[1].Triangles.VertexCount = _countof(Vertices); + Geometries[1].Triangles.IndexCount = (PrimitiveOffsets[2] - PrimitiveOffsets[1]) * 3; + Geometries[1].Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; + Geometries[1].Triangles.IndexBuffer = 0; + Geometries[1].Triangles.Transform3x4 = 0; + + Geometries[2].Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + Geometries[2].Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; + Geometries[2].Triangles.VertexBuffer.StartAddress = 0; + Geometries[2].Triangles.VertexBuffer.StrideInBytes = sizeof(Vertices[0]); + Geometries[2].Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; + Geometries[2].Triangles.VertexCount = _countof(Vertices); + Geometries[2].Triangles.IndexCount = (_countof(Primitives) - PrimitiveOffsets[2]) * 3; + Geometries[2].Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; + Geometries[2].Triangles.IndexBuffer = 0; + Geometries[2].Triangles.Transform3x4 = 0; + + BottomLevelInputs.pGeometryDescs = Geometries; + BottomLevelInputs.NumDescs = _countof(Geometries); + + TopLevelInputs.NumDescs = _countof(Instances); + + CreateBLAS(Ctx, BottomLevelInputs); + CreateTLAS(Ctx, TopLevelInputs); + CreateRTBuffers(Ctx, sizeof(Vertices), sizeof(Indices), InstanceCount, 1, HitGroupCount, + TestingConstants::MultiGeometry::ShaderRecordSize, + sizeof(PrimitiveOffsets) + sizeof(Primitives)); + + Instances[0].InstanceID = 0; + Instances[0].InstanceContributionToHitGroupIndex = 0; + Instances[0].InstanceMask = 0xFF; + Instances[0].Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE; + Instances[0].AccelerationStructure = Ctx.BLAS.pAS->GetGPUVirtualAddress(); + Instances[0].Transform[0][0] = 1.0f; + Instances[0].Transform[1][1] = 1.0f; + Instances[0].Transform[2][2] = 1.0f; + + Instances[1].InstanceID = 0; + Instances[1].InstanceContributionToHitGroupIndex = HitGroupCount / 2; + Instances[1].InstanceMask = 0xFF; + Instances[1].Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE; + Instances[1].AccelerationStructure = Ctx.BLAS.pAS->GetGPUVirtualAddress(); + Instances[1].Transform[0][0] = 1.0f; + Instances[1].Transform[1][1] = 1.0f; + Instances[1].Transform[2][2] = 1.0f; + Instances[1].Transform[0][3] = 0.1f; + Instances[1].Transform[1][3] = 0.5f; + Instances[1].Transform[2][3] = 0.0f; + + UpdateBuffer(Ctx, Ctx.pVertexBuffer, 0, Vertices, sizeof(Vertices)); + UpdateBuffer(Ctx, Ctx.pIndexBuffer, 0, Indices, sizeof(Indices)); + UpdateBuffer(Ctx, Ctx.pInstanceBuffer, 0, Instances, sizeof(Instances)); + + // vertex & instance buffer barrier + { + std::vector Barriers; + D3D12_RESOURCE_BARRIER Barrier; + + Barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + Barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + Barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + Barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + + if (Ctx.pVertexBuffer) + { + Barrier.Transition.pResource = Ctx.pVertexBuffer; + Barriers.push_back(Barrier); + } + if (Ctx.pIndexBuffer) + { + Barrier.Transition.pResource = Ctx.pIndexBuffer; + Barriers.push_back(Barrier); + } + if (Ctx.pInstanceBuffer) + { + Barrier.Transition.pResource = Ctx.pInstanceBuffer; + Barriers.push_back(Barrier); + } + Ctx.pCmdList->ResourceBarrier(static_cast(Barriers.size()), Barriers.data()); + } + + Geometries[0].Triangles.VertexBuffer.StartAddress = Ctx.pVertexBuffer->GetGPUVirtualAddress(); + Geometries[1].Triangles.VertexBuffer.StartAddress = Ctx.pVertexBuffer->GetGPUVirtualAddress(); + Geometries[2].Triangles.VertexBuffer.StartAddress = Ctx.pVertexBuffer->GetGPUVirtualAddress(); + + Geometries[0].Triangles.IndexBuffer = Ctx.pIndexBuffer->GetGPUVirtualAddress() + PrimitiveOffsets[0] * sizeof(uint) * 3; + Geometries[1].Triangles.IndexBuffer = Ctx.pIndexBuffer->GetGPUVirtualAddress() + PrimitiveOffsets[1] * sizeof(uint) * 3; + Geometries[2].Triangles.IndexBuffer = Ctx.pIndexBuffer->GetGPUVirtualAddress() + PrimitiveOffsets[2] * sizeof(uint) * 3; + + BLASDesc.DestAccelerationStructureData = Ctx.BLAS.pAS->GetGPUVirtualAddress(); + BLASDesc.ScratchAccelerationStructureData = Ctx.pScratchBuffer->GetGPUVirtualAddress(); + BLASDesc.SourceAccelerationStructureData = 0; + + ASSERT_TRUE(BLASDesc.DestAccelerationStructureData != 0); + ASSERT_TRUE(BLASDesc.ScratchAccelerationStructureData != 0); + + Ctx.pCmdList->BuildRaytracingAccelerationStructure(&BLASDesc, 0, nullptr); + + // UAV barrier for scratch buffer + { + D3D12_RESOURCE_BARRIER Barrier; + Barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + Barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + Barrier.UAV.pResource = Ctx.pScratchBuffer; + + Ctx.pCmdList->ResourceBarrier(1, &Barrier); + } + + TopLevelInputs.InstanceDescs = Ctx.pInstanceBuffer->GetGPUVirtualAddress(); + + TLASDesc.DestAccelerationStructureData = Ctx.TLAS.pAS->GetGPUVirtualAddress(); + TLASDesc.ScratchAccelerationStructureData = Ctx.pScratchBuffer->GetGPUVirtualAddress(); + TLASDesc.SourceAccelerationStructureData = 0; + + ASSERT_TRUE(TLASDesc.DestAccelerationStructureData != 0); + ASSERT_TRUE(TLASDesc.ScratchAccelerationStructureData != 0); + + Ctx.pCmdList->BuildRaytracingAccelerationStructure(&TLASDesc, 0, nullptr); + } + + // update descriptors + CComPtr pPerInstanceBuffer; + CComPtr pPrimitiveBuffer; + { + D3D12_RESOURCE_DESC BuffDesc = {}; + BuffDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + BuffDesc.Alignment = 0; + BuffDesc.Width = sizeof(PrimitiveOffsets); + BuffDesc.Height = 1; + BuffDesc.DepthOrArraySize = 1; + BuffDesc.MipLevels = 1; + BuffDesc.Format = DXGI_FORMAT_UNKNOWN; + BuffDesc.SampleDesc.Count = 1; + BuffDesc.SampleDesc.Quality = 0; + BuffDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + BuffDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + D3D12_HEAP_PROPERTIES HeapProps; + HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + HeapProps.CreationNodeMask = 1; + HeapProps.VisibleNodeMask = 1; + + auto hr = Ctx.pDevice->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, + &BuffDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + IID_PPV_ARGS(&pPerInstanceBuffer)); + ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to create per instance buffer"; + + BuffDesc.Width = sizeof(Primitives); + + hr = Ctx.pDevice->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, + &BuffDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + IID_PPV_ARGS(&pPrimitiveBuffer)); + ASSERT_HRESULT_SUCCEEDED(hr) << "Failed to create per instance buffer"; + + UpdateBuffer(Ctx, pPrimitiveBuffer, 0, Primitives, sizeof(Primitives)); + UpdateBuffer(Ctx, pPerInstanceBuffer, 0, PrimitiveOffsets, sizeof(PrimitiveOffsets)); + + // buffer barrier + { + D3D12_RESOURCE_BARRIER Barrier = {}; + Barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + Barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + Barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + Barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + Barrier.Transition.pResource = pPerInstanceBuffer; + Ctx.pCmdList->ResourceBarrier(1, &Barrier); + + Barrier.Transition.pResource = pPrimitiveBuffer; + Ctx.pCmdList->ResourceBarrier(1, &Barrier); + } + + D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {}; + D3D12_CPU_DESCRIPTOR_HANDLE SRVHandle; + + SRVDesc.Format = DXGI_FORMAT_UNKNOWN; + SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + SRVDesc.Buffer.NumElements = _countof(Vertices); + SRVDesc.Buffer.StructureByteStride = sizeof(Vertices[0]); + + ASSERT_LT(Ctx.DescHeapCount, Ctx.DescriptorHeapSize); + ASSERT_TRUE(Ctx.DescHeapCount == 2); + SRVHandle = Ctx.pDescHeap->GetCPUDescriptorHandleForHeapStart(); + SRVHandle.ptr += Ctx.DescHandleSize * Ctx.DescHeapCount++; + Ctx.pDevice->CreateShaderResourceView(Ctx.pVertexBuffer, &SRVDesc, SRVHandle); // g_Vertices + + SRVDesc.Buffer.NumElements = _countof(Primitives); + SRVDesc.Buffer.StructureByteStride = sizeof(Primitives[0]); + ASSERT_LT(Ctx.DescHeapCount, Ctx.DescriptorHeapSize); + ASSERT_TRUE(Ctx.DescHeapCount == 3); + SRVHandle = Ctx.pDescHeap->GetCPUDescriptorHandleForHeapStart(); + SRVHandle.ptr += Ctx.DescHandleSize * Ctx.DescHeapCount++; + Ctx.pDevice->CreateShaderResourceView(pPrimitiveBuffer, &SRVDesc, SRVHandle); // g_Primitives + + SRVDesc.Buffer.NumElements = _countof(PrimitiveOffsets); + SRVDesc.Buffer.StructureByteStride = sizeof(PrimitiveOffsets[0]); + ASSERT_LT(Ctx.DescHeapCount, Ctx.DescriptorHeapSize); + ASSERT_TRUE(Ctx.DescHeapCount == 4); + SRVHandle = Ctx.pDescHeap->GetCPUDescriptorHandleForHeapStart(); + SRVHandle.ptr += Ctx.DescHandleSize * Ctx.DescHeapCount++; + Ctx.pDevice->CreateShaderResourceView(pPerInstanceBuffer, &SRVDesc, SRVHandle); // g_PerInstance[0] + + ASSERT_TRUE(Ctx.DescHeapCount == 5); + SRVHandle = Ctx.pDescHeap->GetCPUDescriptorHandleForHeapStart(); + SRVHandle.ptr += Ctx.DescHandleSize * Ctx.DescHeapCount++; + Ctx.pDevice->CreateShaderResourceView(pPerInstanceBuffer, &SRVDesc, SRVHandle); // g_PerInstance[1] + } + + Ctx.ClearRenderTarget(pTestingSwapChainD3D12); + + // trace rays + { + pTestingSwapChainD3D12->TransitionRenderTarget(Ctx.pCmdList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + + ID3D12DescriptorHeap* DescHeaps[] = {Ctx.pDescHeap}; + + Ctx.pCmdList->SetPipelineState1(Ctx.pRayTracingSO); + Ctx.pCmdList->SetComputeRootSignature(Ctx.pGlobalRootSignature); + + Ctx.pCmdList->SetDescriptorHeaps(_countof(DescHeaps), &DescHeaps[0]); + Ctx.pCmdList->SetComputeRootDescriptorTable(0, DescHeaps[0]->GetGPUDescriptorHandleForHeapStart()); + + D3D12_DISPATCH_RAYS_DESC Desc = {}; + + Desc.Width = SCDesc.Width; + Desc.Height = SCDesc.Height; + Desc.Depth = 1; + + const UINT64 handleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + const UINT64 align = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; + const UINT64 ShaderRecordSize = handleSize + TestingConstants::MultiGeometry::ShaderRecordSize; + const size_t RayGenOffset = 0; + const size_t RayMissOffset = Align(RayGenOffset + handleSize, align); + const size_t HitGroupOffset = Align(RayMissOffset + handleSize, align); + const auto& Weights = TestingConstants::MultiGeometry::Weights; + + Desc.RayGenerationShaderRecord.StartAddress = Ctx.pSBTBuffer->GetGPUVirtualAddress() + RayGenOffset; + Desc.RayGenerationShaderRecord.SizeInBytes = ShaderRecordSize; + Desc.MissShaderTable.StartAddress = Ctx.pSBTBuffer->GetGPUVirtualAddress() + RayMissOffset; + Desc.MissShaderTable.SizeInBytes = ShaderRecordSize; + Desc.MissShaderTable.StrideInBytes = ShaderRecordSize; + Desc.HitGroupTable.StartAddress = Ctx.pSBTBuffer->GetGPUVirtualAddress() + HitGroupOffset; + Desc.HitGroupTable.SizeInBytes = ShaderRecordSize * HitGroupCount; + Desc.HitGroupTable.StrideInBytes = ShaderRecordSize; + + UpdateBuffer(Ctx, Ctx.pSBTBuffer, RayGenOffset, Ctx.pStateObjectProperties->GetShaderIdentifier(L"Main"), handleSize); + UpdateBuffer(Ctx, Ctx.pSBTBuffer, RayMissOffset, Ctx.pStateObjectProperties->GetShaderIdentifier(L"Miss"), handleSize); + + const auto SetHitGroup = [&](Uint32 Index, const wchar_t* GroupName, const void* ShaderRecord) { + VERIFY_EXPR(Index < HitGroupCount); + UINT64 Offset = HitGroupOffset + Index * ShaderRecordSize; + UpdateBuffer(Ctx, Ctx.pSBTBuffer, Offset, Ctx.pStateObjectProperties->GetShaderIdentifier(GroupName), handleSize); + UpdateBuffer(Ctx, Ctx.pSBTBuffer, Offset + handleSize, ShaderRecord, sizeof(Weights[0])); + }; + // instance 1 + SetHitGroup(0, L"HitGroup1", &Weights[2]); // geometry 1 + SetHitGroup(1, L"HitGroup1", &Weights[0]); // geometry 2 + SetHitGroup(2, L"HitGroup1", &Weights[1]); // geometry 3 + // instance 2 + SetHitGroup(3, L"HitGroup2", &Weights[2]); // geometry 1 + SetHitGroup(4, L"HitGroup2", &Weights[1]); // geometry 2 + SetHitGroup(5, L"HitGroup2", &Weights[0]); // geometry 3 + + // SBT buffer barrier + { + D3D12_RESOURCE_BARRIER Barrier; + Barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + Barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + Barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + Barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + Barrier.Transition.pResource = Ctx.pSBTBuffer; + Ctx.pCmdList->ResourceBarrier(1, &Barrier); + } + + Ctx.pCmdList->DispatchRays(&Desc); + } + + Ctx.pCmdList->Close(); + + pEnv->ExecuteCommandList(Ctx.pCmdList, true); +} + } // namespace Testing } // namespace Diligent diff --git a/Tests/DiligentCoreAPITest/src/RayTracingTest.cpp b/Tests/DiligentCoreAPITest/src/RayTracingTest.cpp index bd6b2223..fa71c6a7 100644 --- a/Tests/DiligentCoreAPITest/src/RayTracingTest.cpp +++ b/Tests/DiligentCoreAPITest/src/RayTracingTest.cpp @@ -34,6 +34,7 @@ #include "gtest/gtest.h" #include "InlineShaders/RayTracingTestHLSL.h" +#include "RayTracingTestConstants.hpp" namespace Diligent { @@ -45,12 +46,14 @@ namespace Testing void RayTracingTriangleClosestHitReferenceD3D12(ISwapChain* pSwapChain); void RayTracingTriangleAnyHitReferenceD3D12(ISwapChain* pSwapChain); void RayTracingProceduralIntersectionReferenceD3D12(ISwapChain* pSwapChain); +void RayTracingMultiGeometryReferenceD3D12(ISwapChain* pSwapChain); #endif #if VULKAN_SUPPORTED void RayTracingTriangleClosestHitReferenceVk(ISwapChain* pSwapChain); void RayTracingTriangleAnyHitReferenceVk(ISwapChain* pSwapChain); void RayTracingProceduralIntersectionReferenceVk(ISwapChain* pSwapChain); +void RayTracingMultiGeometryReferenceVk(ISwapChain* pSwapChain); #endif } // namespace Testing @@ -83,6 +86,7 @@ void CreateBLAS(IRenderDevice* pDevice, IDeviceContext* pContext, const BLASBuil BottomLevelASDesc ASDesc; ASDesc.Name = "Triangle BLAS"; + ASDesc.Flags = RAYTRACING_BUILD_AS_NONE; ASDesc.pTriangles = TriangleInfos.data(); ASDesc.TriangleCount = TriangleCount; @@ -130,6 +134,7 @@ void CreateBLAS(IRenderDevice* pDevice, IDeviceContext* pContext, const BLASBuil BottomLevelASDesc ASDesc; ASDesc.Name = "Boxes BLAS"; + ASDesc.Flags = RAYTRACING_BUILD_AS_NONE; ASDesc.pBoxes = BoxInfos.data(); ASDesc.BoxCount = BoxCount; @@ -262,12 +267,12 @@ TEST(RayTracingTest, TriangleClosestHitShader) ShaderCreateInfo ShaderCI; ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; ShaderCI.ShaderCompiler = SHADER_COMPILER_DXC; + ShaderCI.EntryPoint = "main"; // Create ray generation shader. RefCntAutoPtr pRG; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_GEN; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Ray tracing RG"; ShaderCI.Source = HLSL::RayTracingTest1_RG.c_str(); pDevice->CreateShader(ShaderCI, &pRG); @@ -278,7 +283,6 @@ TEST(RayTracingTest, TriangleClosestHitShader) RefCntAutoPtr pRMiss; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_MISS; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Miss shader"; ShaderCI.Source = HLSL::RayTracingTest1_RM.c_str(); pDevice->CreateShader(ShaderCI, &pRMiss); @@ -289,7 +293,6 @@ TEST(RayTracingTest, TriangleClosestHitShader) RefCntAutoPtr pClosestHit; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_CLOSEST_HIT; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Ray closest hit shader"; ShaderCI.Source = HLSL::RayTracingTest1_RCH.c_str(); pDevice->CreateShader(ShaderCI, &pClosestHit); @@ -315,12 +318,7 @@ TEST(RayTracingTest, TriangleClosestHitShader) pRayTracingPSO->CreateShaderResourceBinding(&pRayTracingSRB, true); VERIFY_EXPR(pRayTracingSRB != nullptr); - const float3 Vertices[] = // - { - float3{0.25f, 0.25f, 0.0f}, - float3{0.75f, 0.25f, 0.0f}, - float3{0.50f, 0.75f, 0.0f} // - }; + const auto& Vertices = TestingConstants::TriangleClosestHit::Vertices; RefCntAutoPtr pVertexBuffer; { @@ -351,15 +349,9 @@ TEST(RayTracingTest, TriangleClosestHitShader) CreateBLAS(pDevice, pContext, &Triangle, 1, pBLAS); TLASBuildInstanceData Instance; - Instance.InstanceName = "Instance"; - Instance.pBLAS = pBLAS; - Instance.CustomId = 0; - Instance.Flags = RAYTRACING_INSTANCE_NONE; - Instance.Mask = 0xFF; - Instance.ContributionToHitGroupIndex = 0; - Instance.Transform[0][0] = 1.0f; - Instance.Transform[1][1] = 1.0f; - Instance.Transform[2][2] = 1.0f; + Instance.InstanceName = "Instance"; + Instance.pBLAS = pBLAS; + Instance.Flags = RAYTRACING_INSTANCE_NONE; RefCntAutoPtr pTLAS; CreateTLAS(pDevice, pContext, &Instance, 1, pTLAS); @@ -367,7 +359,6 @@ TEST(RayTracingTest, TriangleClosestHitShader) ShaderBindingTableDesc SBTDesc; SBTDesc.Name = "SBT"; SBTDesc.pPSO = pRayTracingPSO; - SBTDesc.ShaderRecordSize = 0; SBTDesc.HitShadersPerInstance = 1; RefCntAutoPtr pSBT; @@ -447,12 +438,12 @@ TEST(RayTracingTest, TriangleAnyHitShader) ShaderCreateInfo ShaderCI; ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; ShaderCI.ShaderCompiler = SHADER_COMPILER_DXC; + ShaderCI.EntryPoint = "main"; // Create ray generation shader. RefCntAutoPtr pRG; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_GEN; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Ray tracing RG"; ShaderCI.Source = HLSL::RayTracingTest2_RG.c_str(); pDevice->CreateShader(ShaderCI, &pRG); @@ -463,7 +454,6 @@ TEST(RayTracingTest, TriangleAnyHitShader) RefCntAutoPtr pRMiss; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_MISS; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Miss shader"; ShaderCI.Source = HLSL::RayTracingTest2_RM.c_str(); pDevice->CreateShader(ShaderCI, &pRMiss); @@ -474,7 +464,6 @@ TEST(RayTracingTest, TriangleAnyHitShader) RefCntAutoPtr pClosestHit; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_CLOSEST_HIT; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Ray closest hit shader"; ShaderCI.Source = HLSL::RayTracingTest2_RCH.c_str(); pDevice->CreateShader(ShaderCI, &pClosestHit); @@ -485,7 +474,6 @@ TEST(RayTracingTest, TriangleAnyHitShader) RefCntAutoPtr pAnyHit; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_ANY_HIT; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Ray any hit shader"; ShaderCI.Source = HLSL::RayTracingTest2_RAH.c_str(); pDevice->CreateShader(ShaderCI, &pAnyHit); @@ -511,12 +499,7 @@ TEST(RayTracingTest, TriangleAnyHitShader) pRayTracingPSO->CreateShaderResourceBinding(&pRayTracingSRB, true); VERIFY_EXPR(pRayTracingSRB != nullptr); - const float3 Vertices[] = // - { - float3{0.25f, 0.25f, 0.0f}, float3{0.75f, 0.25f, 0.0f}, float3{0.50f, 0.75f, 0.0f}, - float3{0.50f, 0.10f, 0.1f}, float3{0.90f, 0.90f, 0.1f}, float3{0.10f, 0.90f, 0.1f}, - float3{0.40f, 1.00f, 0.2f}, float3{0.20f, 0.40f, 0.2f}, float3{1.00f, 0.70f, 0.2f} // - }; + const auto& Vertices = TestingConstants::TriangleAnyHit::Vertices; RefCntAutoPtr pVertexBuffer; { @@ -547,15 +530,9 @@ TEST(RayTracingTest, TriangleAnyHitShader) CreateBLAS(pDevice, pContext, &Triangle, 1, pBLAS); TLASBuildInstanceData Instance; - Instance.InstanceName = "Instance"; - Instance.pBLAS = pBLAS; - Instance.CustomId = 0; - Instance.Flags = RAYTRACING_INSTANCE_NONE; - Instance.Mask = 0xFF; - Instance.ContributionToHitGroupIndex = 0; - Instance.Transform[0][0] = 1.0f; - Instance.Transform[1][1] = 1.0f; - Instance.Transform[2][2] = 1.0f; + Instance.InstanceName = "Instance"; + Instance.pBLAS = pBLAS; + Instance.Flags = RAYTRACING_INSTANCE_NONE; RefCntAutoPtr pTLAS; CreateTLAS(pDevice, pContext, &Instance, 1, pTLAS); @@ -563,7 +540,6 @@ TEST(RayTracingTest, TriangleAnyHitShader) ShaderBindingTableDesc SBTDesc; SBTDesc.Name = "SBT"; SBTDesc.pPSO = pRayTracingPSO; - SBTDesc.ShaderRecordSize = 0; SBTDesc.HitShadersPerInstance = 1; RefCntAutoPtr pSBT; @@ -643,12 +619,12 @@ TEST(RayTracingTest, ProceduralIntersection) ShaderCreateInfo ShaderCI; ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; ShaderCI.ShaderCompiler = SHADER_COMPILER_DXC; + ShaderCI.EntryPoint = "main"; // Create ray generation shader. RefCntAutoPtr pRG; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_GEN; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Ray tracing RG"; ShaderCI.Source = HLSL::RayTracingTest3_RG.c_str(); pDevice->CreateShader(ShaderCI, &pRG); @@ -659,7 +635,6 @@ TEST(RayTracingTest, ProceduralIntersection) RefCntAutoPtr pRMiss; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_MISS; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Miss shader"; ShaderCI.Source = HLSL::RayTracingTest3_RM.c_str(); pDevice->CreateShader(ShaderCI, &pRMiss); @@ -670,7 +645,6 @@ TEST(RayTracingTest, ProceduralIntersection) RefCntAutoPtr pClosestHit; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_CLOSEST_HIT; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Ray closest hit shader"; ShaderCI.Source = HLSL::RayTracingTest3_RCH.c_str(); pDevice->CreateShader(ShaderCI, &pClosestHit); @@ -681,7 +655,6 @@ TEST(RayTracingTest, ProceduralIntersection) RefCntAutoPtr pIntersection; { ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_INTERSECTION; - ShaderCI.EntryPoint = "main"; ShaderCI.Desc.Name = "Ray intersection shader"; ShaderCI.Source = HLSL::RayTracingTest3_RI.c_str(); pDevice->CreateShader(ShaderCI, &pIntersection); @@ -707,9 +680,7 @@ TEST(RayTracingTest, ProceduralIntersection) pRayTracingPSO->CreateShaderResourceBinding(&pRayTracingSRB, true); VERIFY_EXPR(pRayTracingSRB != nullptr); - const float3 Boxes[] = { - float3{0.25f, 0.5f, 2.0f} - float3{1.0f, 1.0f, 1.0f}, - float3{0.25f, 0.5f, 2.0f} + float3{1.0f, 1.0f, 1.0f}}; + const auto& Boxes = TestingConstants::ProceduralIntersection::Boxes; RefCntAutoPtr pBoxBuffer; { @@ -738,15 +709,9 @@ TEST(RayTracingTest, ProceduralIntersection) CreateBLAS(pDevice, pContext, &Box, 1, pBLAS); TLASBuildInstanceData Instance; - Instance.InstanceName = "Instance"; - Instance.pBLAS = pBLAS; - Instance.CustomId = 0; - Instance.Flags = RAYTRACING_INSTANCE_NONE; - Instance.Mask = 0xFF; - Instance.ContributionToHitGroupIndex = 0; - Instance.Transform[0][0] = 1.0f; - Instance.Transform[1][1] = 1.0f; - Instance.Transform[2][2] = 1.0f; + Instance.InstanceName = "Instance"; + Instance.pBLAS = pBLAS; + Instance.Flags = RAYTRACING_INSTANCE_NONE; RefCntAutoPtr pTLAS; CreateTLAS(pDevice, pContext, &Instance, 1, pTLAS); @@ -754,7 +719,6 @@ TEST(RayTracingTest, ProceduralIntersection) ShaderBindingTableDesc SBTDesc; SBTDesc.Name = "SBT"; SBTDesc.pPSO = pRayTracingPSO; - SBTDesc.ShaderRecordSize = 0; SBTDesc.HitShadersPerInstance = 1; RefCntAutoPtr pSBT; @@ -784,4 +748,261 @@ TEST(RayTracingTest, ProceduralIntersection) pSwapChain->Present(); } + +TEST(RayTracingTest, MultiGeometry) +{ + auto* pEnv = TestingEnvironment::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + if (!pDevice->GetDeviceCaps().Features.RayTracing) + { + GTEST_SKIP() << "Ray tracing is not supported by this device"; + } + + auto* pSwapChain = pEnv->GetSwapChain(); + auto* pContext = pEnv->GetDeviceContext(); + + RefCntAutoPtr pTestingSwapChain(pSwapChain, IID_TestingSwapChain); + if (pTestingSwapChain) + { + pContext->Flush(); + pContext->InvalidateState(); + + auto deviceType = pDevice->GetDeviceCaps().DevType; + switch (deviceType) + { +#if D3D12_SUPPORTED + case RENDER_DEVICE_TYPE_D3D12: + RayTracingMultiGeometryReferenceD3D12(pSwapChain); + break; +#endif + +#if VULKAN_SUPPORTED + case RENDER_DEVICE_TYPE_VULKAN: + RayTracingMultiGeometryReferenceVk(pSwapChain); + break; +#endif + + default: + LOG_ERROR_AND_THROW("Unsupported device type"); + } + + pTestingSwapChain->TakeSnapshot(); + } + TestingEnvironment::ScopedReleaseResources EnvironmentAutoReset; + + RayTracingPipelineStateCreateInfo PSOCreateInfo; + + PSOCreateInfo.PSODesc.Name = "Ray tracing PSO"; + PSOCreateInfo.PSODesc.PipelineType = PIPELINE_TYPE_RAY_TRACING; + + ShaderCreateInfo ShaderCI; + ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; + ShaderCI.ShaderCompiler = SHADER_COMPILER_DXC; + ShaderCI.EntryPoint = "main"; + + // Create ray generation shader. + RefCntAutoPtr pRG; + { + ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_GEN; + ShaderCI.Desc.Name = "Ray tracing RG"; + ShaderCI.Source = HLSL::RayTracingTest4_RG.c_str(); + pDevice->CreateShader(ShaderCI, &pRG); + VERIFY_EXPR(pRG != nullptr); + } + + // Create ray miss shader. + RefCntAutoPtr pRMiss; + { + ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_MISS; + ShaderCI.Desc.Name = "Miss shader"; + ShaderCI.Source = HLSL::RayTracingTest4_RM.c_str(); + pDevice->CreateShader(ShaderCI, &pRMiss); + VERIFY_EXPR(pRMiss != nullptr); + } + + // Create ray closest hit shader. + RefCntAutoPtr pClosestHit1; + { + ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_CLOSEST_HIT; + ShaderCI.Desc.Name = "Ray closest hit shader 1"; + ShaderCI.Source = HLSL::RayTracingTest4_RCH1.c_str(); + pDevice->CreateShader(ShaderCI, &pClosestHit1); + VERIFY_EXPR(pClosestHit1 != nullptr); + } + + RefCntAutoPtr pClosestHit2; + { + ShaderCI.Desc.ShaderType = SHADER_TYPE_RAY_CLOSEST_HIT; + ShaderCI.Desc.Name = "Ray closest hit shader 2"; + ShaderCI.Source = HLSL::RayTracingTest4_RCH2.c_str(); + pDevice->CreateShader(ShaderCI, &pClosestHit2); + VERIFY_EXPR(pClosestHit2 != nullptr); + } + + const RayTracingGeneralShaderGroup GeneralShaders[] = {{"Main", pRG}, {"Miss", pRMiss}}; + const RayTracingTriangleHitShaderGroup TriangleHitShaders[] = {{"HitGroup1", pClosestHit1}, {"HitGroup2", pClosestHit2}}; + + PSOCreateInfo.pGeneralShaders = GeneralShaders; + PSOCreateInfo.GeneralShaderCount = _countof(GeneralShaders); + PSOCreateInfo.pTriangleHitShaders = TriangleHitShaders; + PSOCreateInfo.TriangleHitShaderCount = _countof(TriangleHitShaders); + + PSOCreateInfo.RayTracingPipeline.MaxRecursionDepth = 0; + + PSOCreateInfo.RayTracingPipeline.ShaderRecordSize = TestingConstants::MultiGeometry::ShaderRecordSize; + PSOCreateInfo.ShaderRecordName = "g_LocalRoot"; + + PSOCreateInfo.PSODesc.ResourceLayout.DefaultVariableType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; + + RefCntAutoPtr pRayTracingPSO; + pDevice->CreateRayTracingPipelineState(PSOCreateInfo, &pRayTracingPSO); + VERIFY_EXPR(pRayTracingPSO != nullptr); + + RefCntAutoPtr pRayTracingSRB; + pRayTracingPSO->CreateShaderResourceBinding(&pRayTracingSRB, true); + VERIFY_EXPR(pRayTracingSRB != nullptr); + + const auto& Vertices = TestingConstants::MultiGeometry::Vertices; + const auto& Indices = TestingConstants::MultiGeometry::Indices; + const auto& Weights = TestingConstants::MultiGeometry::Weights; + const auto& PrimitiveOffsets = TestingConstants::MultiGeometry::PrimitiveOffsets; + const auto& Primitives = TestingConstants::MultiGeometry::Primitives; + + RefCntAutoPtr pVertexBuffer; + RefCntAutoPtr pIndexBuffer; + RefCntAutoPtr pPerInstanceBuffer; + RefCntAutoPtr pPrimitiveBuffer; + { + BufferDesc BuffDesc; + BuffDesc.Name = "Indices"; + BuffDesc.Usage = USAGE_IMMUTABLE; + BuffDesc.BindFlags = BIND_RAY_TRACING; + BuffDesc.uiSizeInBytes = sizeof(Indices); + BufferData BufData = {Indices, sizeof(Indices)}; + pDevice->CreateBuffer(BuffDesc, &BufData, &pIndexBuffer); + VERIFY_EXPR(pIndexBuffer != nullptr); + + BuffDesc.Name = "Vertices"; + BuffDesc.Mode = BUFFER_MODE_STRUCTURED; + BuffDesc.BindFlags = BIND_RAY_TRACING | BIND_SHADER_RESOURCE; + BuffDesc.uiSizeInBytes = sizeof(Vertices); + BuffDesc.ElementByteStride = sizeof(Vertices[0]); + BufData = {Vertices, sizeof(Vertices)}; + pDevice->CreateBuffer(BuffDesc, &BufData, &pVertexBuffer); + VERIFY_EXPR(pVertexBuffer != nullptr); + + BuffDesc.Name = "PerInstanceData"; + BuffDesc.BindFlags = BIND_SHADER_RESOURCE; + BuffDesc.uiSizeInBytes = sizeof(PrimitiveOffsets); + BuffDesc.ElementByteStride = sizeof(PrimitiveOffsets[0]); + BufData = {PrimitiveOffsets, sizeof(PrimitiveOffsets)}; + pDevice->CreateBuffer(BuffDesc, &BufData, &pPerInstanceBuffer); + VERIFY_EXPR(pPerInstanceBuffer != nullptr); + + BuffDesc.Name = "PrimitiveData"; + BuffDesc.uiSizeInBytes = sizeof(Primitives); + BuffDesc.ElementByteStride = sizeof(Primitives[0]); + BufData = {Primitives, sizeof(Primitives)}; + pDevice->CreateBuffer(BuffDesc, &BufData, &pPrimitiveBuffer); + VERIFY_EXPR(pPrimitiveBuffer != nullptr); + } + + BLASBuildTriangleData Triangles[3] = {}; + Triangles[0].GeometryName = "Geom 1"; + Triangles[0].pVertexBuffer = pVertexBuffer; + Triangles[0].VertexStride = sizeof(Vertices[0]); + Triangles[0].VertexCount = _countof(Vertices); + Triangles[0].VertexValueType = VT_FLOAT32; + Triangles[0].VertexComponentCount = 3; + Triangles[0].pIndexBuffer = pIndexBuffer; + Triangles[0].IndexType = VT_UINT32; + Triangles[0].IndexCount = (PrimitiveOffsets[1] - PrimitiveOffsets[0]) * 3; + Triangles[0].IndexOffset = PrimitiveOffsets[0] * sizeof(uint) * 3; + Triangles[0].Flags = RAYTRACING_GEOMETRY_OPAQUE; + + Triangles[1].GeometryName = "Geom 2"; + Triangles[1].pVertexBuffer = pVertexBuffer; + Triangles[1].VertexStride = sizeof(Vertices[0]); + Triangles[1].VertexCount = _countof(Vertices); + Triangles[1].VertexValueType = VT_FLOAT32; + Triangles[1].VertexComponentCount = 3; + Triangles[1].pIndexBuffer = pIndexBuffer; + Triangles[1].IndexType = VT_UINT32; + Triangles[1].IndexCount = (PrimitiveOffsets[2] - PrimitiveOffsets[1]) * 3; + Triangles[1].IndexOffset = PrimitiveOffsets[1] * sizeof(uint) * 3; + Triangles[1].Flags = RAYTRACING_GEOMETRY_OPAQUE; + + Triangles[2].GeometryName = "Geom 3"; + Triangles[2].pVertexBuffer = pVertexBuffer; + Triangles[2].VertexStride = sizeof(Vertices[0]); + Triangles[2].VertexCount = _countof(Vertices); + Triangles[2].VertexValueType = VT_FLOAT32; + Triangles[2].VertexComponentCount = 3; + Triangles[2].pIndexBuffer = pIndexBuffer; + Triangles[2].IndexType = VT_UINT32; + Triangles[2].IndexCount = (_countof(Primitives) - PrimitiveOffsets[2]) * 3; + Triangles[2].IndexOffset = PrimitiveOffsets[2] * sizeof(uint) * 3; + Triangles[2].Flags = RAYTRACING_GEOMETRY_OPAQUE; + + RefCntAutoPtr pBLAS; + CreateBLAS(pDevice, pContext, Triangles, _countof(Triangles), pBLAS); + + TLASBuildInstanceData Instances[2] = {}; + + Instances[0].InstanceName = "Instance 1"; + Instances[0].pBLAS = pBLAS; + Instances[0].Flags = RAYTRACING_INSTANCE_NONE; + + Instances[1].InstanceName = "Instance 2"; + Instances[1].pBLAS = pBLAS; + Instances[1].Flags = RAYTRACING_INSTANCE_NONE; + Instances[1].Transform.SetTranslation(0.1f, 0.5f, 0.0f); + + RefCntAutoPtr pTLAS; + CreateTLAS(pDevice, pContext, Instances, _countof(Instances), pTLAS); + + ShaderBindingTableDesc SBTDesc; + SBTDesc.Name = "SBT"; + SBTDesc.pPSO = pRayTracingPSO; + SBTDesc.HitShadersPerInstance = 1; + + RefCntAutoPtr pSBT; + pDevice->CreateSBT(SBTDesc, &pSBT); + VERIFY_EXPR(pSBT != nullptr); + + pSBT->BindRayGenShader("Main"); + pSBT->BindMissShader("Miss", 0); + pSBT->BindHitGroup(pTLAS, "Instance 1", "Geom 1", 0, "HitGroup1", &Weights[2], sizeof(Weights[0])); + pSBT->BindHitGroup(pTLAS, "Instance 1", "Geom 2", 0, "HitGroup1", &Weights[0], sizeof(Weights[0])); + pSBT->BindHitGroup(pTLAS, "Instance 1", "Geom 3", 0, "HitGroup1", &Weights[1], sizeof(Weights[0])); + pSBT->BindHitGroup(pTLAS, "Instance 2", "Geom 1", 0, "HitGroup2", &Weights[2], sizeof(Weights[0])); + pSBT->BindHitGroup(pTLAS, "Instance 2", "Geom 2", 0, "HitGroup2", &Weights[1], sizeof(Weights[0])); + pSBT->BindHitGroup(pTLAS, "Instance 2", "Geom 3", 0, "HitGroup2", &Weights[0], sizeof(Weights[0])); + + pRayTracingSRB->GetVariableByName(SHADER_TYPE_RAY_GEN, "g_TLAS")->Set(pTLAS); + pRayTracingSRB->GetVariableByName(SHADER_TYPE_RAY_GEN, "g_ColorBuffer")->Set(pTestingSwapChain->GetCurrentBackBufferUAV()); + + IDeviceObject* pObject = pPerInstanceBuffer->GetDefaultView(BUFFER_VIEW_SHADER_RESOURCE); + pRayTracingSRB->GetVariableByName(SHADER_TYPE_RAY_CLOSEST_HIT, "g_PerInstance")->SetArray(&pObject, 0, 1); + pRayTracingSRB->GetVariableByName(SHADER_TYPE_RAY_CLOSEST_HIT, "g_PerInstance")->SetArray(&pObject, 1, 1); + + pRayTracingSRB->GetVariableByName(SHADER_TYPE_RAY_CLOSEST_HIT, "g_Primitives")->Set(pPrimitiveBuffer->GetDefaultView(BUFFER_VIEW_SHADER_RESOURCE)); + pRayTracingSRB->GetVariableByName(SHADER_TYPE_RAY_CLOSEST_HIT, "g_Vertices")->Set(pVertexBuffer->GetDefaultView(BUFFER_VIEW_SHADER_RESOURCE)); + + pContext->SetPipelineState(pRayTracingPSO); + pContext->CommitShaderResources(pRayTracingSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + + const auto& SCDesc = pSwapChain->GetDesc(); + + TraceRaysAttribs Attribs; + Attribs.DimensionX = SCDesc.Width; + Attribs.DimensionY = SCDesc.Height; + Attribs.pSBT = pSBT; + Attribs.TransitionMode = RESOURCE_STATE_TRANSITION_MODE_TRANSITION; + + pContext->TraceRays(Attribs); + + pSwapChain->Present(); +} + } // namespace diff --git a/Tests/DiligentCoreAPITest/src/Vulkan/RayTracingReferenceVk.cpp b/Tests/DiligentCoreAPITest/src/Vulkan/RayTracingReferenceVk.cpp index 20788602..6c98a047 100644 --- a/Tests/DiligentCoreAPITest/src/Vulkan/RayTracingReferenceVk.cpp +++ b/Tests/DiligentCoreAPITest/src/Vulkan/RayTracingReferenceVk.cpp @@ -37,6 +37,7 @@ #include "volk/volk.h" #include "InlineShaders/RayTracingTestGLSL.h" +#include "RayTracingTestConstants.hpp" namespace Diligent { @@ -49,20 +50,36 @@ namespace struct RTContext { - VkDevice vkDevice = VK_NULL_HANDLE; - VkCommandBuffer vkCmdBuffer = VK_NULL_HANDLE; - VkImage vkRenderTarget = VK_NULL_HANDLE; - VkImageView vkRenderTargetView = VK_NULL_HANDLE; - VkPipelineLayout vkLayout = VK_NULL_HANDLE; - VkPipeline vkPipeline = VK_NULL_HANDLE; - VkDescriptorSetLayout vkSetLayout = VK_NULL_HANDLE; - VkDescriptorPool vkDescriptorPool = VK_NULL_HANDLE; - VkDescriptorSet vkDescriptorSet = VK_NULL_HANDLE; - VkDeviceMemory vkBLASMemory = VK_NULL_HANDLE; - VkAccelerationStructureKHR vkBLAS = VK_NULL_HANDLE; - VkDeviceAddress vkBLASAddress = 0; - VkDeviceMemory vkTLASMemory = VK_NULL_HANDLE; - VkAccelerationStructureKHR vkTLAS = VK_NULL_HANDLE; + struct AccelStruct + { + VkDevice vkDevice = VK_NULL_HANDLE; + VkDeviceMemory vkMemory = VK_NULL_HANDLE; + VkAccelerationStructureKHR vkAS = VK_NULL_HANDLE; + VkDeviceAddress vkAddress = 0; + + AccelStruct() + {} + + ~AccelStruct() + { + if (vkAS) + vkDestroyAccelerationStructureKHR(vkDevice, vkAS, nullptr); + if (vkMemory) + vkFreeMemory(vkDevice, vkMemory, nullptr); + } + }; + + VkDevice vkDevice = VK_NULL_HANDLE; + VkCommandBuffer vkCmdBuffer = VK_NULL_HANDLE; + VkImage vkRenderTarget = VK_NULL_HANDLE; + VkImageView vkRenderTargetView = VK_NULL_HANDLE; + VkPipelineLayout vkLayout = VK_NULL_HANDLE; + VkPipeline vkPipeline = VK_NULL_HANDLE; + VkDescriptorSetLayout vkSetLayout = VK_NULL_HANDLE; + VkDescriptorPool vkDescriptorPool = VK_NULL_HANDLE; + VkDescriptorSet vkDescriptorSet = VK_NULL_HANDLE; + AccelStruct BLAS; + AccelStruct TLAS; VkBuffer vkSBTBuffer = VK_NULL_HANDLE; VkBuffer vkScratchBuffer = VK_NULL_HANDLE; VkBuffer vkInstanceBuffer = VK_NULL_HANDLE; @@ -73,7 +90,6 @@ struct RTContext VkDeviceAddress vkVertexBufferAddress = 0; VkDeviceAddress vkIndexBufferAddress = 0; VkDeviceMemory vkBufferMemory = VK_NULL_HANDLE; - VkPhysicalDeviceMemoryProperties MemoryProperties = {}; VkPhysicalDeviceLimits DeviceLimits = {}; VkPhysicalDeviceRayTracingPropertiesKHR RayTracingProps = {}; @@ -88,16 +104,8 @@ struct RTContext vkDestroyPipelineLayout(vkDevice, vkLayout, nullptr); if (vkSetLayout) vkDestroyDescriptorSetLayout(vkDevice, vkSetLayout, nullptr); - if (vkBLAS) - vkDestroyAccelerationStructureKHR(vkDevice, vkBLAS, nullptr); - if (vkTLAS) - vkDestroyAccelerationStructureKHR(vkDevice, vkTLAS, nullptr); if (vkDescriptorPool) vkDestroyDescriptorPool(vkDevice, vkDescriptorPool, nullptr); - if (vkBLASMemory) - vkFreeMemory(vkDevice, vkBLASMemory, nullptr); - if (vkTLASMemory) - vkFreeMemory(vkDevice, vkTLASMemory, nullptr); if (vkBufferMemory) vkFreeMemory(vkDevice, vkBufferMemory, nullptr); if (vkSBTBuffer) @@ -136,8 +144,6 @@ void InitializeRTContext(RTContext& Ctx, ISwapChain* pSwapChain, PSOCtorType&& P Ctx.vkRenderTarget = pTestingSwapChainVk->GetVkRenderTargetImage(); Ctx.vkRenderTargetView = pTestingSwapChainVk->GetVkRenderTargetImageView(); - vkGetPhysicalDeviceMemoryProperties(pEnv->GetVkPhysicalDevice(), &Ctx.MemoryProperties); - VkPhysicalDeviceProperties2 Props2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; Props2.pNext = &Ctx.RayTracingProps; Ctx.RayTracingProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR; @@ -225,7 +231,7 @@ void InitializeRTContext(RTContext& Ctx, ISwapChain* pSwapChain, PSOCtorType&& P PoolSizes[0].descriptorCount = MaxDescriptorsInPool; PoolSizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; PoolSizes[1].descriptorCount = MaxDescriptorsInPool; - PoolSizes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; + PoolSizes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; PoolSizes[2].descriptorCount = MaxDescriptorsInPool; res = vkCreateDescriptorPool(Ctx.vkDevice, &DescriptorPoolCI, nullptr, &Ctx.vkDescriptorPool); @@ -269,14 +275,16 @@ void UpdateDescriptorSet(RTContext& Ctx) TLASInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; TLASInfo.accelerationStructureCount = 1; - TLASInfo.pAccelerationStructures = &Ctx.vkTLAS; + TLASInfo.pAccelerationStructures = &Ctx.TLAS.vkAS; DescriptorWrite[1].pNext = &TLASInfo; vkUpdateDescriptorSets(Ctx.vkDevice, _countof(DescriptorWrite), DescriptorWrite, 0, nullptr); } -void CreateBLAS(RTContext& Ctx, const VkAccelerationStructureCreateGeometryTypeInfoKHR* pGeometries, Uint32 GeometryCount) +void CreateBLAS(const RTContext& Ctx, const VkAccelerationStructureCreateGeometryTypeInfoKHR* pGeometries, Uint32 GeometryCount, RTContext::AccelStruct& BLAS) { + BLAS.vkDevice = Ctx.vkDevice; + VkResult res = VK_SUCCESS; VkAccelerationStructureCreateInfoKHR BLASCI = {}; @@ -290,12 +298,12 @@ void CreateBLAS(RTContext& Ctx, const VkAccelerationStructureCreateGeometryTypeI BLASCI.compactedSize = 0; BLASCI.pGeometryInfos = pGeometries; - res = vkCreateAccelerationStructureKHR(Ctx.vkDevice, &BLASCI, nullptr, &Ctx.vkBLAS); + res = vkCreateAccelerationStructureKHR(Ctx.vkDevice, &BLASCI, nullptr, &BLAS.vkAS); ASSERT_GE(res, VK_SUCCESS); - ASSERT_TRUE(Ctx.vkBLAS != VK_NULL_HANDLE); + ASSERT_TRUE(BLAS.vkAS != VK_NULL_HANDLE); MemInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR; - MemInfo.accelerationStructure = Ctx.vkBLAS; + MemInfo.accelerationStructure = BLAS.vkAS; MemInfo.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; MemInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR; @@ -307,32 +315,21 @@ void CreateBLAS(RTContext& Ctx, const VkAccelerationStructureCreateGeometryTypeI MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; MemAlloc.allocationSize = MemReqs.memoryRequirements.size; - MemAlloc.memoryTypeIndex = ~0u; - - for (Uint32 i = 0; i < Ctx.MemoryProperties.memoryTypeCount; ++i) - { - const auto PropFlags = Ctx.MemoryProperties.memoryTypes[i].propertyFlags; - - if (!!(MemReqs.memoryRequirements.memoryTypeBits & (1u << i)) && !!(PropFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) - { - MemAlloc.memoryTypeIndex = i; - break; - } - } + MemAlloc.memoryTypeIndex = TestingEnvironmentVk::GetInstance()->GetMemoryTypeIndex(MemReqs.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); ASSERT_TRUE(MemAlloc.memoryTypeIndex != ~0u); - res = vkAllocateMemory(Ctx.vkDevice, &MemAlloc, nullptr, &Ctx.vkBLASMemory); + res = vkAllocateMemory(Ctx.vkDevice, &MemAlloc, nullptr, &BLAS.vkMemory); ASSERT_GE(res, VK_SUCCESS); - ASSERT_TRUE(Ctx.vkBLASMemory != VK_NULL_HANDLE); + ASSERT_TRUE(BLAS.vkMemory != VK_NULL_HANDLE); VkBindAccelerationStructureMemoryInfoKHR BindInfo = {}; BindInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR; - BindInfo.memory = Ctx.vkBLASMemory; + BindInfo.memory = BLAS.vkMemory; BindInfo.memoryOffset = 0; BindInfo.deviceIndexCount = 0; BindInfo.pDeviceIndices = nullptr; - BindInfo.accelerationStructure = Ctx.vkBLAS; + BindInfo.accelerationStructure = BLAS.vkAS; res = vkBindAccelerationStructureMemoryKHR(Ctx.vkDevice, 1, &BindInfo); ASSERT_GE(res, VK_SUCCESS); @@ -340,13 +337,15 @@ void CreateBLAS(RTContext& Ctx, const VkAccelerationStructureCreateGeometryTypeI VkAccelerationStructureDeviceAddressInfoKHR AddressInfo = {}; AddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; - AddressInfo.accelerationStructure = Ctx.vkBLAS; + AddressInfo.accelerationStructure = BLAS.vkAS; - Ctx.vkBLASAddress = vkGetAccelerationStructureDeviceAddressKHR(Ctx.vkDevice, &AddressInfo); + BLAS.vkAddress = vkGetAccelerationStructureDeviceAddressKHR(Ctx.vkDevice, &AddressInfo); } -void CreateTLAS(RTContext& Ctx, Uint32 InstanceCount) +void CreateTLAS(const RTContext& Ctx, Uint32 InstanceCount, RTContext::AccelStruct& TLAS) { + TLAS.vkDevice = Ctx.vkDevice; + VkResult res = VK_SUCCESS; VkAccelerationStructureCreateInfoKHR TLASCI = {}; @@ -365,12 +364,12 @@ void CreateTLAS(RTContext& Ctx, Uint32 InstanceCount) TLASCI.maxGeometryCount = 1; TLASCI.pGeometryInfos = &Instances; - res = vkCreateAccelerationStructureKHR(Ctx.vkDevice, &TLASCI, nullptr, &Ctx.vkTLAS); + res = vkCreateAccelerationStructureKHR(Ctx.vkDevice, &TLASCI, nullptr, &TLAS.vkAS); ASSERT_GE(res, VK_SUCCESS); - ASSERT_TRUE(Ctx.vkTLAS != VK_NULL_HANDLE); + ASSERT_TRUE(TLAS.vkAS != VK_NULL_HANDLE); MemInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR; - MemInfo.accelerationStructure = Ctx.vkTLAS; + MemInfo.accelerationStructure = TLAS.vkAS; MemInfo.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; MemInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR; @@ -382,39 +381,34 @@ void CreateTLAS(RTContext& Ctx, Uint32 InstanceCount) MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; MemAlloc.allocationSize = MemReqs.memoryRequirements.size; - MemAlloc.memoryTypeIndex = ~0u; - - for (Uint32 i = 0; i < Ctx.MemoryProperties.memoryTypeCount; ++i) - { - const auto PropFlags = Ctx.MemoryProperties.memoryTypes[i].propertyFlags; - - if (!!(MemReqs.memoryRequirements.memoryTypeBits & (1u << i)) && !!(PropFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) - { - MemAlloc.memoryTypeIndex = i; - break; - } - } + MemAlloc.memoryTypeIndex = TestingEnvironmentVk::GetInstance()->GetMemoryTypeIndex(MemReqs.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); ASSERT_TRUE(MemAlloc.memoryTypeIndex != ~0u); - res = vkAllocateMemory(Ctx.vkDevice, &MemAlloc, nullptr, &Ctx.vkTLASMemory); + res = vkAllocateMemory(Ctx.vkDevice, &MemAlloc, nullptr, &TLAS.vkMemory); ASSERT_GE(res, VK_SUCCESS); - ASSERT_TRUE(Ctx.vkTLASMemory != VK_NULL_HANDLE); + ASSERT_TRUE(TLAS.vkMemory != VK_NULL_HANDLE); VkBindAccelerationStructureMemoryInfoKHR BindInfo = {}; BindInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR; - BindInfo.memory = Ctx.vkTLASMemory; + BindInfo.memory = TLAS.vkMemory; BindInfo.memoryOffset = 0; BindInfo.deviceIndexCount = 0; BindInfo.pDeviceIndices = nullptr; - BindInfo.accelerationStructure = Ctx.vkTLAS; + BindInfo.accelerationStructure = TLAS.vkAS; res = vkBindAccelerationStructureMemoryKHR(Ctx.vkDevice, 1, &BindInfo); ASSERT_GE(res, VK_SUCCESS); + + VkAccelerationStructureDeviceAddressInfoKHR AddressInfo = {}; + + AddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; + AddressInfo.accelerationStructure = TLAS.vkAS; + + TLAS.vkAddress = vkGetAccelerationStructureDeviceAddressKHR(Ctx.vkDevice, &AddressInfo); } -template -void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 InstanceCount, Uint32 NumMissShaders, Uint32 NumHitShaders, TCreateBufferFn&& CreateBufferFn) +void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 InstanceCount, Uint32 NumMissShaders, Uint32 NumHitShaders, Uint32 ShaderRecordSize = 0) { VkResult res = VK_SUCCESS; @@ -431,9 +425,9 @@ void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 Instan MemInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR; MemInfo.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; - if (Ctx.vkBLAS) + if (Ctx.BLAS.vkAS) { - MemInfo.accelerationStructure = Ctx.vkBLAS; + MemInfo.accelerationStructure = Ctx.BLAS.vkAS; MemInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR; vkGetAccelerationStructureMemoryRequirementsKHR(Ctx.vkDevice, &MemInfo, &MemReqs); @@ -444,9 +438,9 @@ void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 Instan ScratchSize = std::max(ScratchSize, MemReqs.memoryRequirements.size); } - if (Ctx.vkTLAS) + if (Ctx.TLAS.vkAS) { - MemInfo.accelerationStructure = Ctx.vkTLAS; + MemInfo.accelerationStructure = Ctx.TLAS.vkAS; MemInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR; vkGetAccelerationStructureMemoryRequirementsKHR(Ctx.vkDevice, &MemInfo, &MemReqs); @@ -466,7 +460,7 @@ void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 Instan BufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; BuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - BuffCI.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + BuffCI.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; MemInfo.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2; std::vector> BindMem; @@ -569,9 +563,11 @@ void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 Instan // SBT { - BuffCI.size = Align(Ctx.RayTracingProps.shaderGroupBaseAlignment, Ctx.RayTracingProps.shaderGroupHandleSize); - BuffCI.size = Align(BuffCI.size + Ctx.RayTracingProps.shaderGroupHandleSize * NumMissShaders, Ctx.RayTracingProps.shaderGroupBaseAlignment); - BuffCI.size = Align(BuffCI.size + Ctx.RayTracingProps.shaderGroupHandleSize * NumHitShaders, Ctx.RayTracingProps.shaderGroupBaseAlignment); + const Uint32 GroupSize = Ctx.RayTracingProps.shaderGroupHandleSize + ShaderRecordSize; + + BuffCI.size = Align(GroupSize, Ctx.RayTracingProps.shaderGroupBaseAlignment); + BuffCI.size = Align(BuffCI.size + GroupSize * NumMissShaders, Ctx.RayTracingProps.shaderGroupBaseAlignment); + BuffCI.size = Align(BuffCI.size + GroupSize * NumHitShaders, Ctx.RayTracingProps.shaderGroupBaseAlignment); res = vkCreateBuffer(Ctx.vkDevice, &BuffCI, nullptr, &Ctx.vkSBTBuffer); ASSERT_GE(res, VK_SUCCESS); @@ -591,31 +587,18 @@ void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 Instan }); } - CreateBufferFn(MemSize, MemTypeBits, BindMem); - VkMemoryAllocateInfo MemAlloc = {}; VkMemoryAllocateFlagsInfo MemFlagInfo = {}; MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; MemAlloc.allocationSize = MemSize; - MemAlloc.memoryTypeIndex = ~0u; + MemAlloc.memoryTypeIndex = TestingEnvironmentVk::GetInstance()->GetMemoryTypeIndex(MemReqs.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + ASSERT_TRUE(MemAlloc.memoryTypeIndex != ~0u); MemAlloc.pNext = &MemFlagInfo; MemFlagInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; MemFlagInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; - for (Uint32 i = 0; i < Ctx.MemoryProperties.memoryTypeCount; ++i) - { - const auto PropFlags = Ctx.MemoryProperties.memoryTypes[i].propertyFlags; - - if (!!(MemTypeBits & (1u << i)) && !!(PropFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) - { - MemAlloc.memoryTypeIndex = i; - break; - } - } - ASSERT_TRUE(MemAlloc.memoryTypeIndex != ~0u); - res = vkAllocateMemory(Ctx.vkDevice, &MemAlloc, nullptr, &Ctx.vkBufferMemory); ASSERT_GE(res, VK_SUCCESS); ASSERT_TRUE(Ctx.vkBufferMemory != VK_NULL_HANDLE); @@ -628,9 +611,15 @@ void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 Instan ASSERT_GE(MemSize, Offset); } -void CreateRTBuffers(RTContext& Ctx, Uint32 VBSize, Uint32 IBSize, Uint32 InstanceCount, Uint32 NumMissShaders, Uint32 NumHitShaders) +void ClearRenderTarget(RTContext& Ctx, TestingSwapChainVk* pTestingSwapChainVk) { - return CreateRTBuffers(Ctx, VBSize, IBSize, InstanceCount, NumMissShaders, NumHitShaders, [](auto& MemSize, auto& MemTypeBits, auto& BindMem) {}); + pTestingSwapChainVk->TransitionRenderTarget(Ctx.vkCmdBuffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0); + + VkImageSubresourceRange Range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + VkClearColorValue ClearValue = {}; + vkCmdClearColorImage(Ctx.vkCmdBuffer, Ctx.vkRenderTarget, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &ClearValue, 1, &Range); + + pTestingSwapChainVk->TransitionRenderTarget(Ctx.vkCmdBuffer, VK_IMAGE_LAYOUT_GENERAL, 0); } } // namespace @@ -709,12 +698,7 @@ void RayTracingTriangleClosestHitReferenceVk(ISwapChain* pSwapChain) VkMemoryBarrier Barrier = {}; Barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; - const float3 Vertices[] = // - { - float3{0.25f, 0.25f, 0.0f}, - float3{0.75f, 0.25f, 0.0f}, - float3{0.50f, 0.75f, 0.0f} // - }; + const auto& Vertices = TestingConstants::TriangleClosestHit::Vertices; VkAccelerationStructureCreateGeometryTypeInfoKHR GeometryCI = {}; @@ -726,11 +710,11 @@ void RayTracingTriangleClosestHitReferenceVk(ISwapChain* pSwapChain) GeometryCI.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; GeometryCI.allowsTransforms = VK_FALSE; - CreateBLAS(Ctx, &GeometryCI, 1); - CreateTLAS(Ctx, 1); + CreateBLAS(Ctx, &GeometryCI, 1, Ctx.BLAS); + CreateTLAS(Ctx, 1, Ctx.TLAS); CreateRTBuffers(Ctx, sizeof(Vertices), 0, 1, 1, 1); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkVertexBuffer, 0, sizeof(Vertices), &Vertices); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkVertexBuffer, 0, sizeof(Vertices), Vertices); // barrier for vertex & index buffers Barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -746,16 +730,14 @@ void RayTracingTriangleClosestHitReferenceVk(ISwapChain* pSwapChain) VkAccelerationStructureGeometryKHR const* GeometryPtr = &Geometry; VkAccelerationStructureBuildOffsetInfoKHR const* OffsetPtr = &Offset; - Geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - Geometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - Geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - Geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; - Geometry.geometry.triangles.vertexFormat = GeometryCI.vertexFormat; - Geometry.geometry.triangles.vertexStride = sizeof(Vertices[0]); - Geometry.geometry.triangles.vertexData.deviceAddress = Ctx.vkVertexBufferAddress; - Geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_KHR; - Geometry.geometry.triangles.indexData.deviceAddress = 0; - Geometry.geometry.triangles.transformData.deviceAddress = 0; + Geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + Geometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + Geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + Geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + Geometry.geometry.triangles.vertexFormat = GeometryCI.vertexFormat; + Geometry.geometry.triangles.vertexStride = sizeof(Vertices[0]); + Geometry.geometry.triangles.vertexData.deviceAddress = Ctx.vkVertexBufferAddress; + Geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_KHR; Offset.primitiveCount = GeometryCI.maxPrimitiveCount; Offset.firstVertex = 0; @@ -767,7 +749,7 @@ void RayTracingTriangleClosestHitReferenceVk(ISwapChain* pSwapChain) ASBuildInfo.flags = 0; ASBuildInfo.update = VK_FALSE; ASBuildInfo.srcAccelerationStructure = VK_NULL_HANDLE; - ASBuildInfo.dstAccelerationStructure = Ctx.vkBLAS; + ASBuildInfo.dstAccelerationStructure = Ctx.BLAS.vkAS; ASBuildInfo.geometryArrayOfPointers = VK_FALSE; ASBuildInfo.geometryCount = 1; ASBuildInfo.ppGeometries = &GeometryPtr; @@ -780,7 +762,7 @@ void RayTracingTriangleClosestHitReferenceVk(ISwapChain* pSwapChain) InstanceData.instanceShaderBindingTableRecordOffset = 0; InstanceData.mask = 0xFF; InstanceData.flags = 0; - InstanceData.accelerationStructureReference = Ctx.vkBLASAddress; + InstanceData.accelerationStructureReference = Ctx.BLAS.vkAddress; InstanceData.transform.matrix[0][0] = 1.0f; InstanceData.transform.matrix[1][1] = 1.0f; InstanceData.transform.matrix[2][2] = 1.0f; @@ -812,7 +794,7 @@ void RayTracingTriangleClosestHitReferenceVk(ISwapChain* pSwapChain) ASBuildInfo.flags = 0; ASBuildInfo.update = VK_FALSE; ASBuildInfo.srcAccelerationStructure = VK_NULL_HANDLE; - ASBuildInfo.dstAccelerationStructure = Ctx.vkTLAS; + ASBuildInfo.dstAccelerationStructure = Ctx.TLAS.vkAS; ASBuildInfo.geometryArrayOfPointers = VK_FALSE; ASBuildInfo.geometryCount = 1; ASBuildInfo.ppGeometries = &GeometryPtr; @@ -831,33 +813,34 @@ void RayTracingTriangleClosestHitReferenceVk(ISwapChain* pSwapChain) VkStridedBufferRegionKHR MissShaderBindingTable = {}; VkStridedBufferRegionKHR HitShaderBindingTable = {}; VkStridedBufferRegionKHR CallableShaderBindingTable = {}; + const Uint32 ShaderGroupHandleSize = Ctx.RayTracingProps.shaderGroupHandleSize; RaygenShaderBindingTable.buffer = Ctx.vkSBTBuffer; RaygenShaderBindingTable.offset = 0; - RaygenShaderBindingTable.size = Ctx.RayTracingProps.shaderGroupHandleSize; - MissShaderBindingTable.stride = Ctx.RayTracingProps.shaderGroupHandleSize; + RaygenShaderBindingTable.size = ShaderGroupHandleSize; + MissShaderBindingTable.stride = ShaderGroupHandleSize; MissShaderBindingTable.buffer = Ctx.vkSBTBuffer; MissShaderBindingTable.offset = Align(RaygenShaderBindingTable.offset + RaygenShaderBindingTable.size, Ctx.RayTracingProps.shaderGroupBaseAlignment); - MissShaderBindingTable.size = Ctx.RayTracingProps.shaderGroupHandleSize; - MissShaderBindingTable.stride = Ctx.RayTracingProps.shaderGroupHandleSize; + MissShaderBindingTable.size = ShaderGroupHandleSize; + MissShaderBindingTable.stride = ShaderGroupHandleSize; HitShaderBindingTable.buffer = Ctx.vkSBTBuffer; HitShaderBindingTable.offset = Align(MissShaderBindingTable.offset + MissShaderBindingTable.size, Ctx.RayTracingProps.shaderGroupBaseAlignment); - HitShaderBindingTable.size = Ctx.RayTracingProps.shaderGroupHandleSize; - HitShaderBindingTable.stride = Ctx.RayTracingProps.shaderGroupHandleSize; + HitShaderBindingTable.size = ShaderGroupHandleSize; + HitShaderBindingTable.stride = ShaderGroupHandleSize; char ShaderHandle[64] = {}; - ASSERT_GE(sizeof(ShaderHandle), Ctx.RayTracingProps.shaderGroupHandleSize); + ASSERT_GE(sizeof(ShaderHandle), ShaderGroupHandleSize); - vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, RAYGEN_GROUP, 1, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, RaygenShaderBindingTable.offset, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, RAYGEN_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, RaygenShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); - vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, MISS_GROUP, 1, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, MissShaderBindingTable.offset, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, MISS_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, MissShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); - vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, HIT_GROUP, 1, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, HitShaderBindingTable.offset, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, HIT_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, HitShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); // Barriers for TLAS & SBT VkMemoryBarrier Barrier = {}; @@ -965,12 +948,7 @@ void RayTracingTriangleAnyHitReferenceVk(ISwapChain* pSwapChain) VkMemoryBarrier Barrier = {}; Barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; - const float3 Vertices[] = // - { - float3{0.25f, 0.25f, 0.0f}, float3{0.75f, 0.25f, 0.0f}, float3{0.50f, 0.75f, 0.0f}, - float3{0.50f, 0.10f, 0.1f}, float3{0.90f, 0.90f, 0.1f}, float3{0.10f, 0.90f, 0.1f}, - float3{0.40f, 1.00f, 0.2f}, float3{0.20f, 0.40f, 0.2f}, float3{1.00f, 0.70f, 0.2f} // - }; + const auto& Vertices = TestingConstants::TriangleAnyHit::Vertices; VkAccelerationStructureCreateGeometryTypeInfoKHR GeometryCI = {}; @@ -982,11 +960,11 @@ void RayTracingTriangleAnyHitReferenceVk(ISwapChain* pSwapChain) GeometryCI.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; GeometryCI.allowsTransforms = VK_FALSE; - CreateBLAS(Ctx, &GeometryCI, 1); - CreateTLAS(Ctx, 1); + CreateBLAS(Ctx, &GeometryCI, 1, Ctx.BLAS); + CreateTLAS(Ctx, 1, Ctx.TLAS); CreateRTBuffers(Ctx, sizeof(Vertices), 0, 1, 1, 1); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkVertexBuffer, 0, sizeof(Vertices), &Vertices); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkVertexBuffer, 0, sizeof(Vertices), Vertices); // barrier for vertex & index buffers Barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -1002,16 +980,14 @@ void RayTracingTriangleAnyHitReferenceVk(ISwapChain* pSwapChain) VkAccelerationStructureGeometryKHR const* GeometryPtr = &Geometry; VkAccelerationStructureBuildOffsetInfoKHR const* OffsetPtr = &Offset; - Geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - Geometry.flags = 0; - Geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - Geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; - Geometry.geometry.triangles.vertexFormat = GeometryCI.vertexFormat; - Geometry.geometry.triangles.vertexStride = sizeof(Vertices[0]); - Geometry.geometry.triangles.vertexData.deviceAddress = Ctx.vkVertexBufferAddress; - Geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_KHR; - Geometry.geometry.triangles.indexData.deviceAddress = 0; - Geometry.geometry.triangles.transformData.deviceAddress = 0; + Geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + Geometry.flags = 0; + Geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + Geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + Geometry.geometry.triangles.vertexFormat = GeometryCI.vertexFormat; + Geometry.geometry.triangles.vertexStride = sizeof(Vertices[0]); + Geometry.geometry.triangles.vertexData.deviceAddress = Ctx.vkVertexBufferAddress; + Geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_KHR; Offset.primitiveCount = GeometryCI.maxPrimitiveCount; Offset.firstVertex = 0; @@ -1023,7 +999,7 @@ void RayTracingTriangleAnyHitReferenceVk(ISwapChain* pSwapChain) ASBuildInfo.flags = 0; ASBuildInfo.update = VK_FALSE; ASBuildInfo.srcAccelerationStructure = VK_NULL_HANDLE; - ASBuildInfo.dstAccelerationStructure = Ctx.vkBLAS; + ASBuildInfo.dstAccelerationStructure = Ctx.BLAS.vkAS; ASBuildInfo.geometryArrayOfPointers = VK_FALSE; ASBuildInfo.geometryCount = 1; ASBuildInfo.ppGeometries = &GeometryPtr; @@ -1036,7 +1012,7 @@ void RayTracingTriangleAnyHitReferenceVk(ISwapChain* pSwapChain) InstanceData.instanceShaderBindingTableRecordOffset = 0; InstanceData.mask = 0xFF; InstanceData.flags = 0; - InstanceData.accelerationStructureReference = Ctx.vkBLASAddress; + InstanceData.accelerationStructureReference = Ctx.BLAS.vkAddress; InstanceData.transform.matrix[0][0] = 1.0f; InstanceData.transform.matrix[1][1] = 1.0f; InstanceData.transform.matrix[2][2] = 1.0f; @@ -1068,7 +1044,7 @@ void RayTracingTriangleAnyHitReferenceVk(ISwapChain* pSwapChain) ASBuildInfo.flags = 0; ASBuildInfo.update = VK_FALSE; ASBuildInfo.srcAccelerationStructure = VK_NULL_HANDLE; - ASBuildInfo.dstAccelerationStructure = Ctx.vkTLAS; + ASBuildInfo.dstAccelerationStructure = Ctx.TLAS.vkAS; ASBuildInfo.geometryArrayOfPointers = VK_FALSE; ASBuildInfo.geometryCount = 1; ASBuildInfo.ppGeometries = &GeometryPtr; @@ -1087,33 +1063,34 @@ void RayTracingTriangleAnyHitReferenceVk(ISwapChain* pSwapChain) VkStridedBufferRegionKHR MissShaderBindingTable = {}; VkStridedBufferRegionKHR HitShaderBindingTable = {}; VkStridedBufferRegionKHR CallableShaderBindingTable = {}; + const Uint32 ShaderGroupHandleSize = Ctx.RayTracingProps.shaderGroupHandleSize; RaygenShaderBindingTable.buffer = Ctx.vkSBTBuffer; RaygenShaderBindingTable.offset = 0; - RaygenShaderBindingTable.size = Ctx.RayTracingProps.shaderGroupHandleSize; - MissShaderBindingTable.stride = Ctx.RayTracingProps.shaderGroupHandleSize; + RaygenShaderBindingTable.size = ShaderGroupHandleSize; + MissShaderBindingTable.stride = ShaderGroupHandleSize; MissShaderBindingTable.buffer = Ctx.vkSBTBuffer; MissShaderBindingTable.offset = Align(RaygenShaderBindingTable.offset + RaygenShaderBindingTable.size, Ctx.RayTracingProps.shaderGroupBaseAlignment); - MissShaderBindingTable.size = Ctx.RayTracingProps.shaderGroupHandleSize; - MissShaderBindingTable.stride = Ctx.RayTracingProps.shaderGroupHandleSize; + MissShaderBindingTable.size = ShaderGroupHandleSize; + MissShaderBindingTable.stride = ShaderGroupHandleSize; HitShaderBindingTable.buffer = Ctx.vkSBTBuffer; HitShaderBindingTable.offset = Align(MissShaderBindingTable.offset + MissShaderBindingTable.size, Ctx.RayTracingProps.shaderGroupBaseAlignment); - HitShaderBindingTable.size = Ctx.RayTracingProps.shaderGroupHandleSize; - HitShaderBindingTable.stride = Ctx.RayTracingProps.shaderGroupHandleSize; + HitShaderBindingTable.size = ShaderGroupHandleSize; + HitShaderBindingTable.stride = ShaderGroupHandleSize; char ShaderHandle[64] = {}; - ASSERT_GE(sizeof(ShaderHandle), Ctx.RayTracingProps.shaderGroupHandleSize); + ASSERT_GE(sizeof(ShaderHandle), ShaderGroupHandleSize); - vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, RAYGEN_GROUP, 1, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, RaygenShaderBindingTable.offset, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, RAYGEN_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, RaygenShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); - vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, MISS_GROUP, 1, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, MissShaderBindingTable.offset, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, MISS_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, MissShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); - vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, HIT_GROUP, 1, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, HitShaderBindingTable.offset, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, HIT_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, HitShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); // Barriers for TLAS & SBT VkMemoryBarrier Barrier = {}; @@ -1221,11 +1198,7 @@ void RayTracingProceduralIntersectionReferenceVk(ISwapChain* pSwapChain) VkMemoryBarrier Barrier = {}; Barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; - const float3 Boxes[] = // - { - float3{0.25f, 0.5f, 2.0f} - float3{1.0f, 1.0f, 1.0f}, - float3{0.25f, 0.5f, 2.0f} + float3{1.0f, 1.0f, 1.0f} // - }; + const auto& Boxes = TestingConstants::ProceduralIntersection::Boxes; VkAccelerationStructureCreateGeometryTypeInfoKHR GeometryCI = {}; @@ -1234,11 +1207,11 @@ void RayTracingProceduralIntersectionReferenceVk(ISwapChain* pSwapChain) GeometryCI.maxPrimitiveCount = 1; GeometryCI.indexType = VK_INDEX_TYPE_NONE_KHR; - CreateBLAS(Ctx, &GeometryCI, 1); - CreateTLAS(Ctx, 1); + CreateBLAS(Ctx, &GeometryCI, 1, Ctx.BLAS); + CreateTLAS(Ctx, 1, Ctx.TLAS); CreateRTBuffers(Ctx, sizeof(Boxes), 0, 1, 1, 1); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkVertexBuffer, 0, sizeof(Boxes), &Boxes); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkVertexBuffer, 0, sizeof(Boxes), Boxes); // barrier for vertex & index buffers Barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -1272,7 +1245,7 @@ void RayTracingProceduralIntersectionReferenceVk(ISwapChain* pSwapChain) ASBuildInfo.flags = 0; ASBuildInfo.update = VK_FALSE; ASBuildInfo.srcAccelerationStructure = VK_NULL_HANDLE; - ASBuildInfo.dstAccelerationStructure = Ctx.vkBLAS; + ASBuildInfo.dstAccelerationStructure = Ctx.BLAS.vkAS; ASBuildInfo.geometryArrayOfPointers = VK_FALSE; ASBuildInfo.geometryCount = 1; ASBuildInfo.ppGeometries = &GeometryPtr; @@ -1285,7 +1258,7 @@ void RayTracingProceduralIntersectionReferenceVk(ISwapChain* pSwapChain) InstanceData.instanceShaderBindingTableRecordOffset = 0; InstanceData.mask = 0xFF; InstanceData.flags = 0; - InstanceData.accelerationStructureReference = Ctx.vkBLASAddress; + InstanceData.accelerationStructureReference = Ctx.BLAS.vkAddress; InstanceData.transform.matrix[0][0] = 1.0f; InstanceData.transform.matrix[1][1] = 1.0f; InstanceData.transform.matrix[2][2] = 1.0f; @@ -1317,7 +1290,7 @@ void RayTracingProceduralIntersectionReferenceVk(ISwapChain* pSwapChain) ASBuildInfo.flags = 0; ASBuildInfo.update = VK_FALSE; ASBuildInfo.srcAccelerationStructure = VK_NULL_HANDLE; - ASBuildInfo.dstAccelerationStructure = Ctx.vkTLAS; + ASBuildInfo.dstAccelerationStructure = Ctx.TLAS.vkAS; ASBuildInfo.geometryArrayOfPointers = VK_FALSE; ASBuildInfo.geometryCount = 1; ASBuildInfo.ppGeometries = &GeometryPtr; @@ -1336,33 +1309,34 @@ void RayTracingProceduralIntersectionReferenceVk(ISwapChain* pSwapChain) VkStridedBufferRegionKHR MissShaderBindingTable = {}; VkStridedBufferRegionKHR HitShaderBindingTable = {}; VkStridedBufferRegionKHR CallableShaderBindingTable = {}; + const Uint32 ShaderGroupHandleSize = Ctx.RayTracingProps.shaderGroupHandleSize; RaygenShaderBindingTable.buffer = Ctx.vkSBTBuffer; RaygenShaderBindingTable.offset = 0; - RaygenShaderBindingTable.size = Ctx.RayTracingProps.shaderGroupHandleSize; - MissShaderBindingTable.stride = Ctx.RayTracingProps.shaderGroupHandleSize; + RaygenShaderBindingTable.size = ShaderGroupHandleSize; + MissShaderBindingTable.stride = ShaderGroupHandleSize; MissShaderBindingTable.buffer = Ctx.vkSBTBuffer; MissShaderBindingTable.offset = Align(RaygenShaderBindingTable.offset + RaygenShaderBindingTable.size, Ctx.RayTracingProps.shaderGroupBaseAlignment); - MissShaderBindingTable.size = Ctx.RayTracingProps.shaderGroupHandleSize; - MissShaderBindingTable.stride = Ctx.RayTracingProps.shaderGroupHandleSize; + MissShaderBindingTable.size = ShaderGroupHandleSize; + MissShaderBindingTable.stride = ShaderGroupHandleSize; HitShaderBindingTable.buffer = Ctx.vkSBTBuffer; HitShaderBindingTable.offset = Align(MissShaderBindingTable.offset + MissShaderBindingTable.size, Ctx.RayTracingProps.shaderGroupBaseAlignment); - HitShaderBindingTable.size = Ctx.RayTracingProps.shaderGroupHandleSize; - HitShaderBindingTable.stride = Ctx.RayTracingProps.shaderGroupHandleSize; + HitShaderBindingTable.size = ShaderGroupHandleSize; + HitShaderBindingTable.stride = ShaderGroupHandleSize; char ShaderHandle[64] = {}; - ASSERT_GE(sizeof(ShaderHandle), Ctx.RayTracingProps.shaderGroupHandleSize); + ASSERT_GE(sizeof(ShaderHandle), ShaderGroupHandleSize); - vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, RAYGEN_GROUP, 1, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, RaygenShaderBindingTable.offset, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, RAYGEN_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, RaygenShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); - vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, MISS_GROUP, 1, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, MissShaderBindingTable.offset, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, MISS_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, MissShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); - vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, HIT_GROUP, 1, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); - vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, HitShaderBindingTable.offset, Ctx.RayTracingProps.shaderGroupHandleSize, ShaderHandle); + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, HIT_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, HitShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); // barrier for TLAS & SBT VkMemoryBarrier Barrier = {}; @@ -1388,6 +1362,398 @@ void RayTracingProceduralIntersectionReferenceVk(ISwapChain* pSwapChain) pEnv->SubmitCommandBuffer(Ctx.vkCmdBuffer, true); } + +void RayTracingMultiGeometryReferenceVk(ISwapChain* pSwapChain) +{ + static constexpr Uint32 InstanceCount = TestingConstants::MultiGeometry::InstanceCount; + static constexpr Uint32 GeometryCount = 3; + static constexpr Uint32 HitGroupCount = InstanceCount * GeometryCount; + + enum + { + RAYGEN_SHADER, + MISS_SHADER, + HIT_SHADER_1, + HIT_SHADER_2, + NUM_SHADERS + }; + enum + { + RAYGEN_GROUP, + MISS_GROUP, + HIT_GROUP_1, + HIT_GROUP_2, + NUM_GROUPS + }; + + auto* pEnv = TestingEnvironmentVk::GetInstance(); + auto* pTestingSwapChainVk = ValidatedCast(pSwapChain); + + const auto& SCDesc = pSwapChain->GetDesc(); + + RTContext Ctx = {}; + InitializeRTContext(Ctx, pSwapChain, + [pEnv](auto& Bindings, auto& Modules, auto& Stages, auto& Groups) { + Bindings.resize(3); + Bindings[0] = {2u, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, InstanceCount, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, nullptr}; + Bindings[1] = {3u, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, nullptr}; + Bindings[2] = {4u, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, nullptr}; + + Modules.resize(NUM_SHADERS); + Stages.resize(NUM_SHADERS); + Groups.resize(NUM_GROUPS); + + Modules[RAYGEN_SHADER] = pEnv->CreateShaderModule(SHADER_TYPE_RAY_GEN, GLSL::RayTracingTest4_RG); + Stages[RAYGEN_SHADER].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + Stages[RAYGEN_SHADER].stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + Stages[RAYGEN_SHADER].module = Modules[RAYGEN_SHADER]; + Stages[RAYGEN_SHADER].pName = "main"; + + Modules[MISS_SHADER] = pEnv->CreateShaderModule(SHADER_TYPE_RAY_MISS, GLSL::RayTracingTest4_RM); + Stages[MISS_SHADER].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + Stages[MISS_SHADER].stage = VK_SHADER_STAGE_MISS_BIT_KHR; + Stages[MISS_SHADER].module = Modules[MISS_SHADER]; + Stages[MISS_SHADER].pName = "main"; + + Modules[HIT_SHADER_1] = pEnv->CreateShaderModule(SHADER_TYPE_RAY_CLOSEST_HIT, GLSL::RayTracingTest4_RCH1); + Stages[HIT_SHADER_1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + Stages[HIT_SHADER_1].stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + Stages[HIT_SHADER_1].module = Modules[HIT_SHADER_1]; + Stages[HIT_SHADER_1].pName = "main"; + + Modules[HIT_SHADER_2] = pEnv->CreateShaderModule(SHADER_TYPE_RAY_CLOSEST_HIT, GLSL::RayTracingTest4_RCH2); + Stages[HIT_SHADER_2].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + Stages[HIT_SHADER_2].stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + Stages[HIT_SHADER_2].module = Modules[HIT_SHADER_2]; + Stages[HIT_SHADER_2].pName = "main"; + + Groups[RAYGEN_GROUP].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + Groups[RAYGEN_GROUP].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + Groups[RAYGEN_GROUP].generalShader = RAYGEN_SHADER; + Groups[RAYGEN_GROUP].closestHitShader = VK_SHADER_UNUSED_KHR; + Groups[RAYGEN_GROUP].anyHitShader = VK_SHADER_UNUSED_KHR; + Groups[RAYGEN_GROUP].intersectionShader = VK_SHADER_UNUSED_KHR; + + Groups[HIT_GROUP_1].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + Groups[HIT_GROUP_1].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + Groups[HIT_GROUP_1].generalShader = VK_SHADER_UNUSED_KHR; + Groups[HIT_GROUP_1].closestHitShader = HIT_SHADER_1; + Groups[HIT_GROUP_1].anyHitShader = VK_SHADER_UNUSED_KHR; + Groups[HIT_GROUP_1].intersectionShader = VK_SHADER_UNUSED_KHR; + + Groups[HIT_GROUP_2].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + Groups[HIT_GROUP_2].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + Groups[HIT_GROUP_2].generalShader = VK_SHADER_UNUSED_KHR; + Groups[HIT_GROUP_2].closestHitShader = HIT_SHADER_2; + Groups[HIT_GROUP_2].anyHitShader = VK_SHADER_UNUSED_KHR; + Groups[HIT_GROUP_2].intersectionShader = VK_SHADER_UNUSED_KHR; + + Groups[MISS_GROUP].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + Groups[MISS_GROUP].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + Groups[MISS_GROUP].generalShader = MISS_SHADER; + Groups[MISS_GROUP].closestHitShader = VK_SHADER_UNUSED_KHR; + Groups[MISS_GROUP].anyHitShader = VK_SHADER_UNUSED_KHR; + Groups[MISS_GROUP].intersectionShader = VK_SHADER_UNUSED_KHR; + }); + + const auto& PrimitiveOffsets = TestingConstants::MultiGeometry::PrimitiveOffsets; + const auto& Primitives = TestingConstants::MultiGeometry::Primitives; + + // create acceleration structurea + { + VkMemoryBarrier Barrier = {}; + Barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + + const auto& Vertices = TestingConstants::MultiGeometry::Vertices; + const auto& Indices = TestingConstants::MultiGeometry::Indices; + + VkAccelerationStructureCreateGeometryTypeInfoKHR GeometryCI[3] = {}; + + GeometryCI[0].sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR; + GeometryCI[0].geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + GeometryCI[0].maxPrimitiveCount = PrimitiveOffsets[1]; + GeometryCI[0].indexType = VK_INDEX_TYPE_UINT32; + GeometryCI[0].maxVertexCount = _countof(Vertices); + GeometryCI[0].vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; + GeometryCI[0].allowsTransforms = VK_FALSE; + + GeometryCI[1].sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR; + GeometryCI[1].geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + GeometryCI[1].maxPrimitiveCount = PrimitiveOffsets[2] - PrimitiveOffsets[1]; + GeometryCI[1].indexType = VK_INDEX_TYPE_UINT32; + GeometryCI[1].maxVertexCount = _countof(Vertices); + GeometryCI[1].vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; + GeometryCI[1].allowsTransforms = VK_FALSE; + + GeometryCI[2].sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR; + GeometryCI[2].geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + GeometryCI[2].maxPrimitiveCount = _countof(Primitives) - PrimitiveOffsets[2]; + GeometryCI[2].indexType = VK_INDEX_TYPE_UINT32; + GeometryCI[2].maxVertexCount = _countof(Vertices); + GeometryCI[2].vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; + GeometryCI[2].allowsTransforms = VK_FALSE; + + CreateBLAS(Ctx, GeometryCI, _countof(GeometryCI), Ctx.BLAS); + CreateTLAS(Ctx, 1, Ctx.TLAS); + CreateRTBuffers(Ctx, sizeof(Vertices), sizeof(Indices), InstanceCount, 1, HitGroupCount, TestingConstants::MultiGeometry::ShaderRecordSize); + + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkVertexBuffer, 0, sizeof(Vertices), Vertices); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkIndexBuffer, 0, sizeof(Indices), Indices); + + // barrier for vertex & index buffers + Barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + Barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; + vkCmdPipelineBarrier(Ctx.vkCmdBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + 0, 1, &Barrier, 0, nullptr, 0, nullptr); + + VkAccelerationStructureBuildGeometryInfoKHR ASBuildInfo = {}; + VkAccelerationStructureBuildOffsetInfoKHR Offsets[3] = {}; + VkAccelerationStructureGeometryKHR Geometries[3] = {}; + VkAccelerationStructureGeometryKHR const* GeometriyPtr = Geometries; + VkAccelerationStructureBuildOffsetInfoKHR const* OffsetPtr = Offsets; + static_assert(_countof(Offsets) == _countof(Geometries), "size mismatch"); + static_assert(_countof(GeometryCI) == _countof(Geometries), "size mismatch"); + static_assert(GeometryCount == _countof(Geometries), "size mismatch"); + + Geometries[0].sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + Geometries[0].flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + Geometries[0].geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + Geometries[0].geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + Geometries[0].geometry.triangles.vertexFormat = GeometryCI[0].vertexFormat; + Geometries[0].geometry.triangles.vertexStride = sizeof(Vertices[0]); + Geometries[0].geometry.triangles.vertexData.deviceAddress = Ctx.vkVertexBufferAddress; + Geometries[0].geometry.triangles.indexType = GeometryCI[0].indexType; + Geometries[0].geometry.triangles.indexData.deviceAddress = Ctx.vkIndexBufferAddress + PrimitiveOffsets[0] * sizeof(uint) * 3; + + Geometries[1].sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + Geometries[1].flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + Geometries[1].geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + Geometries[1].geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + Geometries[1].geometry.triangles.vertexFormat = GeometryCI[1].vertexFormat; + Geometries[1].geometry.triangles.vertexStride = sizeof(Vertices[0]); + Geometries[1].geometry.triangles.vertexData.deviceAddress = Ctx.vkVertexBufferAddress; + Geometries[1].geometry.triangles.indexType = GeometryCI[1].indexType; + Geometries[1].geometry.triangles.indexData.deviceAddress = Ctx.vkIndexBufferAddress + PrimitiveOffsets[1] * sizeof(uint) * 3; + + Geometries[2].sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + Geometries[2].flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + Geometries[2].geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + Geometries[2].geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + Geometries[2].geometry.triangles.vertexFormat = GeometryCI[2].vertexFormat; + Geometries[2].geometry.triangles.vertexStride = sizeof(Vertices[0]); + Geometries[2].geometry.triangles.vertexData.deviceAddress = Ctx.vkVertexBufferAddress; + Geometries[2].geometry.triangles.indexType = GeometryCI[2].indexType; + Geometries[2].geometry.triangles.indexData.deviceAddress = Ctx.vkIndexBufferAddress + PrimitiveOffsets[2] * sizeof(uint) * 3; + + Offsets[0].primitiveCount = GeometryCI[0].maxPrimitiveCount; + Offsets[1].primitiveCount = GeometryCI[1].maxPrimitiveCount; + Offsets[2].primitiveCount = GeometryCI[2].maxPrimitiveCount; + + ASBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + ASBuildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + ASBuildInfo.flags = 0; + ASBuildInfo.update = VK_FALSE; + ASBuildInfo.srcAccelerationStructure = VK_NULL_HANDLE; + ASBuildInfo.dstAccelerationStructure = Ctx.BLAS.vkAS; + ASBuildInfo.geometryArrayOfPointers = VK_FALSE; + ASBuildInfo.geometryCount = _countof(Geometries); + ASBuildInfo.ppGeometries = &GeometriyPtr; + ASBuildInfo.scratchData.deviceAddress = Ctx.vkScratchBufferAddress; + + vkCmdBuildAccelerationStructureKHR(Ctx.vkCmdBuffer, 1, &ASBuildInfo, &OffsetPtr); + + VkAccelerationStructureInstanceKHR InstanceData[2] = {}; + + InstanceData[0].instanceCustomIndex = 0; + InstanceData[0].instanceShaderBindingTableRecordOffset = 0; + InstanceData[0].mask = 0xFF; + InstanceData[0].flags = 0; + InstanceData[0].accelerationStructureReference = Ctx.BLAS.vkAddress; + InstanceData[0].transform.matrix[0][0] = 1.0f; + InstanceData[0].transform.matrix[1][1] = 1.0f; + InstanceData[0].transform.matrix[2][2] = 1.0f; + + InstanceData[1].instanceCustomIndex = 2; + InstanceData[1].instanceShaderBindingTableRecordOffset = HitGroupCount / 2; + InstanceData[1].mask = 0xFF; + InstanceData[1].flags = 0; + InstanceData[1].accelerationStructureReference = Ctx.BLAS.vkAddress; + InstanceData[1].transform.matrix[0][0] = 1.0f; + InstanceData[1].transform.matrix[1][1] = 1.0f; + InstanceData[1].transform.matrix[2][2] = 1.0f; + InstanceData[1].transform.matrix[0][3] = 0.1f; + InstanceData[1].transform.matrix[1][3] = 0.5f; + InstanceData[1].transform.matrix[2][3] = 0.0f; + + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkInstanceBuffer, 0, sizeof(InstanceData), InstanceData); + + // barrier for BLAS, scratch buffer, instance buffer + Barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_TRANSFER_WRITE_BIT; + Barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; + vkCmdPipelineBarrier(Ctx.vkCmdBuffer, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + 0, 1, &Barrier, 0, nullptr, 0, nullptr); + + VkAccelerationStructureBuildOffsetInfoKHR InstOffsets = {}; + VkAccelerationStructureGeometryKHR Instances[2] = {}; + static_assert(_countof(InstanceData) == _countof(Instances), "size mismatch"); + static_assert(InstanceCount == _countof(Instances), "size mismatch"); + + GeometriyPtr = Instances; + OffsetPtr = &InstOffsets; + InstOffsets.primitiveCount = _countof(Instances); + + Instances[0].flags = 0; + Instances[0].geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + Instances[0].geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + Instances[0].geometry.instances.pNext = nullptr; + Instances[0].geometry.instances.arrayOfPointers = VK_FALSE; + Instances[0].geometry.instances.data.deviceAddress = Ctx.vkInstanceBufferAddress; + + Instances[1].flags = 0; + Instances[1].geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + Instances[1].geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + Instances[1].geometry.instances.pNext = nullptr; + Instances[1].geometry.instances.arrayOfPointers = VK_FALSE; + Instances[1].geometry.instances.data.deviceAddress = Ctx.vkInstanceBufferAddress + sizeof(VkAccelerationStructureInstanceKHR); + + ASBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + ASBuildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + ASBuildInfo.flags = 0; + ASBuildInfo.update = VK_FALSE; + ASBuildInfo.srcAccelerationStructure = VK_NULL_HANDLE; + ASBuildInfo.dstAccelerationStructure = Ctx.TLAS.vkAS; + ASBuildInfo.geometryArrayOfPointers = VK_FALSE; + ASBuildInfo.geometryCount = 1; + ASBuildInfo.ppGeometries = &GeometriyPtr; + ASBuildInfo.scratchData.deviceAddress = Ctx.vkScratchBufferAddress; + + vkCmdBuildAccelerationStructureKHR(Ctx.vkCmdBuffer, 1, &ASBuildInfo, &OffsetPtr); + } + + ClearRenderTarget(Ctx, pTestingSwapChainVk); + UpdateDescriptorSet(Ctx); + + VkBuffer vkPerInstanceBuffer = VK_NULL_HANDLE; + VkDeviceMemory vkPerInstanceBufferMemory = VK_NULL_HANDLE; + VkBuffer vkPrimitiveBuffer = VK_NULL_HANDLE; + VkDeviceMemory vkPrimitiveBufferMemory = VK_NULL_HANDLE; + { + pEnv->CreateBuffer(sizeof(PrimitiveOffsets), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vkPerInstanceBufferMemory, vkPerInstanceBuffer); + pEnv->CreateBuffer(sizeof(Primitives), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vkPrimitiveBufferMemory, vkPrimitiveBuffer); + + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, vkPerInstanceBuffer, 0, sizeof(PrimitiveOffsets), PrimitiveOffsets); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, vkPrimitiveBuffer, 0, sizeof(Primitives), Primitives); + + VkWriteDescriptorSet DescriptorWrite = {}; + VkDescriptorBufferInfo BufInfo = {}; + + DescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + DescriptorWrite.dstSet = Ctx.vkDescriptorSet; + DescriptorWrite.dstBinding = 4; + DescriptorWrite.dstArrayElement = 0; + DescriptorWrite.descriptorCount = 1; + DescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + DescriptorWrite.pBufferInfo = &BufInfo; + BufInfo.buffer = Ctx.vkVertexBuffer; + BufInfo.range = VK_WHOLE_SIZE; + vkUpdateDescriptorSets(Ctx.vkDevice, 1, &DescriptorWrite, 0, nullptr); + + DescriptorWrite.dstBinding = 3; + BufInfo.buffer = vkPrimitiveBuffer; + vkUpdateDescriptorSets(Ctx.vkDevice, 1, &DescriptorWrite, 0, nullptr); + + DescriptorWrite.dstBinding = 2; + BufInfo.buffer = vkPerInstanceBuffer; + vkUpdateDescriptorSets(Ctx.vkDevice, 1, &DescriptorWrite, 0, nullptr); + + DescriptorWrite.dstArrayElement = 1; + vkUpdateDescriptorSets(Ctx.vkDevice, 1, &DescriptorWrite, 0, nullptr); + } + + // trace rays + { + VkStridedBufferRegionKHR RaygenShaderBindingTable = {}; + VkStridedBufferRegionKHR MissShaderBindingTable = {}; + VkStridedBufferRegionKHR HitShaderBindingTable = {}; + VkStridedBufferRegionKHR CallableShaderBindingTable = {}; + const Uint32 ShaderGroupHandleSize = Ctx.RayTracingProps.shaderGroupHandleSize; + const Uint32 ShaderRecordSize = ShaderGroupHandleSize + TestingConstants::MultiGeometry::ShaderRecordSize; + const auto& Weights = TestingConstants::MultiGeometry::Weights; + + RaygenShaderBindingTable.buffer = Ctx.vkSBTBuffer; + RaygenShaderBindingTable.offset = 0; + RaygenShaderBindingTable.size = ShaderRecordSize; + MissShaderBindingTable.stride = ShaderRecordSize; + + MissShaderBindingTable.buffer = Ctx.vkSBTBuffer; + MissShaderBindingTable.offset = Align(RaygenShaderBindingTable.offset + RaygenShaderBindingTable.size, Ctx.RayTracingProps.shaderGroupBaseAlignment); + MissShaderBindingTable.size = ShaderRecordSize; + MissShaderBindingTable.stride = ShaderRecordSize; + + HitShaderBindingTable.buffer = Ctx.vkSBTBuffer; + HitShaderBindingTable.offset = Align(MissShaderBindingTable.offset + MissShaderBindingTable.size, Ctx.RayTracingProps.shaderGroupBaseAlignment); + HitShaderBindingTable.size = ShaderRecordSize * HitGroupCount; + HitShaderBindingTable.stride = ShaderRecordSize; + + char ShaderHandle[64] = {}; + ASSERT_GE(sizeof(ShaderHandle), ShaderGroupHandleSize); + + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, RAYGEN_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, RaygenShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); + + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, MISS_GROUP, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, MissShaderBindingTable.offset, ShaderGroupHandleSize, ShaderHandle); + + const auto SetHitGroup = [&](Uint32 Index, Uint32 ShaderIndex, const void* ShaderRecord) { + VERIFY_EXPR(Index < HitGroupCount); + VkDeviceSize Offset = HitShaderBindingTable.offset + Index * ShaderRecordSize; + vkGetRayTracingShaderGroupHandlesKHR(Ctx.vkDevice, Ctx.vkPipeline, ShaderIndex, 1, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, Offset, ShaderGroupHandleSize, ShaderHandle); + vkCmdUpdateBuffer(Ctx.vkCmdBuffer, Ctx.vkSBTBuffer, Offset + ShaderGroupHandleSize, sizeof(Weights[0]), ShaderRecord); + }; + // instance 1 + SetHitGroup(0, HIT_GROUP_1, &Weights[2]); // geometry 1 + SetHitGroup(1, HIT_GROUP_1, &Weights[0]); // geometry 2 + SetHitGroup(2, HIT_GROUP_1, &Weights[1]); // geometry 3 + // instance 2 + SetHitGroup(3, HIT_GROUP_2, &Weights[2]); // geometry 1 + SetHitGroup(4, HIT_GROUP_2, &Weights[1]); // geometry 2 + SetHitGroup(5, HIT_GROUP_2, &Weights[0]); // geometry 3 + + // barrier for TLAS & SBT + VkMemoryBarrier Barrier = {}; + Barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + Barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_TRANSFER_WRITE_BIT; + Barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; + vkCmdPipelineBarrier(Ctx.vkCmdBuffer, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, + 0, 1, &Barrier, 0, nullptr, 0, nullptr); + + vkCmdBindPipeline(Ctx.vkCmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, Ctx.vkPipeline); + vkCmdBindDescriptorSets(Ctx.vkCmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, Ctx.vkLayout, 0, 1, &Ctx.vkDescriptorSet, 0, nullptr); + + vkCmdTraceRaysKHR(Ctx.vkCmdBuffer, &RaygenShaderBindingTable, &MissShaderBindingTable, &HitShaderBindingTable, &CallableShaderBindingTable, SCDesc.Width, SCDesc.Height, 1); + + pTestingSwapChainVk->TransitionRenderTarget(Ctx.vkCmdBuffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0); + } + + auto res = vkEndCommandBuffer(Ctx.vkCmdBuffer); + VERIFY(res >= 0, "Failed to end command buffer"); + + pEnv->SubmitCommandBuffer(Ctx.vkCmdBuffer, true); + + vkDestroyBuffer(Ctx.vkDevice, vkPerInstanceBuffer, nullptr); + vkDestroyBuffer(Ctx.vkDevice, vkPrimitiveBuffer, nullptr); + vkFreeMemory(Ctx.vkDevice, vkPerInstanceBufferMemory, nullptr); + vkFreeMemory(Ctx.vkDevice, vkPrimitiveBufferMemory, nullptr); +} + + } // namespace Testing } // namespace Diligent -- cgit v1.2.3