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 --- .../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 +- 8 files changed, 338 insertions(+), 82 deletions(-) (limited to 'Graphics/GraphicsEngine') 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_ -- cgit v1.2.3