diff options
| author | azhirnov <zh1dron@gmail.com> | 2020-11-07 19:34:49 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-11-10 03:43:28 +0000 |
| commit | 0f35896a60c4de02ccfc91ace18bcef4450fa4d9 (patch) | |
| tree | 86a772a36c6c2258949231b756970a621b69f82b /Graphics | |
| parent | Corrected ray rtacing vertex format handling in D3D12 (diff) | |
| download | DiligentCore-0f35896a60c4de02ccfc91ace18bcef4450fa4d9.tar.gz DiligentCore-0f35896a60c4de02ccfc91ace18bcef4450fa4d9.zip | |
Added ability to update AS.
Diffstat (limited to 'Graphics')
45 files changed, 1540 insertions, 569 deletions
diff --git a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp index caee8620..8f180004 100644 --- a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp +++ b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp @@ -42,14 +42,26 @@ namespace Diligent { +struct BLASGeomIndex +{ + Uint32 IndexInDesc = INVALID_INDEX; // geometry index in description + Uint32 ActualIndex = INVALID_INDEX; // geometry index in build operation + + BLASGeomIndex() {} + BLASGeomIndex(Uint32 _IndexInDesc, Uint32 _ActualIndex) : + IndexInDesc{_IndexInDesc}, ActualIndex{_ActualIndex} {} +}; +using BLASNameToIndex = std::unordered_map<HashMapStringKey, BLASGeomIndex, HashMapStringKey::Hasher>; + /// Validates bottom-level AS description and throws and exception in case of an error. void ValidateBottomLevelASDesc(const BottomLevelASDesc& Desc) noexcept(false); -/// Copies bottom-level AS description (except for the Name) using MemPool to allocate required dynamic space. -void CopyBottomLevelASDesc(const BottomLevelASDesc& SrcDesc, - BottomLevelASDesc& DstDesc, - LinearAllocator& MemPool, - std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>& NameToIndex) noexcept(false); +/// Copies bottom-level AS geometry description using MemPool to allocate required dynamic space. +void CopyBLASGeometryDesc(const BottomLevelASDesc& SrcDesc, + BottomLevelASDesc& DstDesc, + LinearAllocator& MemPool, + const BLASNameToIndex* pSrcNameToIndex, + BLASNameToIndex& DstNameToIndex) noexcept(false); /// Template class implementing base functionality for a bottom-level acceleration structure object. @@ -82,32 +94,65 @@ public: } else { - CopyDescriptionUnsafe(Desc); + CopyGeometryDescriptionUnsafe(Desc, nullptr); } } ~BottomLevelASBase() { - Clear(); + ClearGeometry(); } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BottomLevelAS, TDeviceObjectBase) - virtual Uint32 DILIGENT_CALL_TYPE GetGeometryIndex(const char* Name) const override final + // Map geometry that used in build operation to geometry description. + // Returns geometry index in geometry description. + Uint32 UpdateGeometryIndex(const char* Name, Uint32& ActualIndex, bool OnUpdate) { VERIFY_EXPR(Name != nullptr && Name[0] != '\0'); auto iter = m_NameToIndex.find(Name); if (iter != m_NameToIndex.end()) - return iter->second; + { + if (OnUpdate) + ActualIndex = iter->second.ActualIndex; + else + iter->second.ActualIndex = ActualIndex; + return iter->second.IndexInDesc; + } + LOG_ERROR_MESSAGE("Can't find geometry with name '", Name, '\''); + return INVALID_INDEX; + } + + virtual Uint32 DILIGENT_CALL_TYPE GetGeometryDescIndex(const char* Name) const override final + { + VERIFY_EXPR(Name != nullptr && Name[0] != '\0'); + + auto iter = m_NameToIndex.find(Name); + if (iter != m_NameToIndex.end()) + return iter->second.IndexInDesc; + + LOG_ERROR_MESSAGE("Can't find geometry with name '", Name, '\''); + return INVALID_INDEX; + } + + virtual Uint32 DILIGENT_CALL_TYPE GetGeometryIndex(const char* Name) const override final + { + VERIFY_EXPR(Name != nullptr && Name[0] != '\0'); + auto iter = m_NameToIndex.find(Name); + if (iter != m_NameToIndex.end()) + { + VERIFY(iter->second.ActualIndex != INVALID_INDEX, "Geometry exists but not enabled during last build"); + return iter->second.ActualIndex; + } LOG_ERROR_MESSAGE("Can't find geometry with name '", Name, '\''); - return InvalidGeometryIndex; + return INVALID_INDEX; } virtual void DILIGENT_CALL_TYPE SetState(RESOURCE_STATE State) override final { - VERIFY(State == RESOURCE_STATE_BUILD_AS_READ || State == RESOURCE_STATE_BUILD_AS_WRITE, + VERIFY(State == RESOURCE_STATE_UNKNOWN || State == RESOURCE_STATE_BUILD_AS_READ || State == RESOURCE_STATE_BUILD_AS_WRITE, "Unsupported state for a bottom-level acceleration structure"); this->m_State = State; } @@ -118,7 +163,7 @@ public: } /// Implementation of IBottomLevelAS::GetScratchBufferSizes() - virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override + virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override final { return this->m_ScratchSize; } @@ -138,44 +183,48 @@ public: #ifdef DILIGENT_DEVELOPMENT void UpdateVersion() { - m_Version.fetch_add(1); + this->m_DbgVersion.fetch_add(1); } Uint32 GetVersion() const { - return m_Version.load(); - } - - bool ValidateContent() const - { - // AZ TODO - return true; + return this->m_DbgVersion.load(); } #endif // DILIGENT_DEVELOPMENT - void CopyDescription(const BottomLevelASBase& SrcBLAS) noexcept + void CopyGeometryDescription(const BottomLevelASBase& SrcBLAS) noexcept { - Clear(); + ClearGeometry(); try { - CopyDescriptionUnsafe(SrcBLAS.GetDesc()); + CopyGeometryDescriptionUnsafe(SrcBLAS.GetDesc(), &SrcBLAS.m_NameToIndex); } catch (...) { - Clear(); + ClearGeometry(); } } + void SetActualGeometryCount(Uint32 Count) + { + m_GeometryCount = Count; + } + + virtual Uint32 DILIGENT_CALL_TYPE GetActualGeometryCount() const override final + { + return m_GeometryCount; + } + private: - void CopyDescriptionUnsafe(const BottomLevelASDesc& SrcDesc) noexcept(false) + void CopyGeometryDescriptionUnsafe(const BottomLevelASDesc& SrcDesc, const BLASNameToIndex* pSrcNameToIndex) noexcept(false) { LinearAllocator MemPool{GetRawAllocator()}; - CopyBottomLevelASDesc(SrcDesc, this->m_Desc, MemPool, m_NameToIndex); + CopyBLASGeometryDesc(SrcDesc, this->m_Desc, MemPool, pSrcNameToIndex, this->m_NameToIndex); this->m_pRawPtr = MemPool.Release(); } - void Clear() noexcept + void ClearGeometry() noexcept { if (this->m_pRawPtr != nullptr) { @@ -183,25 +232,24 @@ private: this->m_pRawPtr = nullptr; } - // Preserve original name - it was allocated by DeviceObjectBase - auto* Name = this->m_Desc.Name; - this->m_Desc = BottomLevelASDesc{}; - this->m_Desc.Name = Name; + // keep Name, Flags, CompactedSize, CommandQueueMask + this->m_Desc.pTriangles = nullptr; + this->m_Desc.TriangleCount = 0; + this->m_Desc.pBoxes = nullptr; + this->m_Desc.BoxCount = 0; m_NameToIndex.clear(); } protected: - RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN; - - std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher> m_NameToIndex; - - void* m_pRawPtr = nullptr; - + RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN; + BLASNameToIndex m_NameToIndex; + void* m_pRawPtr = nullptr; + Uint32 m_GeometryCount = 0; ScratchBufferSizes m_ScratchSize; #ifdef DILIGENT_DEVELOPMENT - std::atomic<Uint32> m_Version{0}; + std::atomic<Uint32> m_DbgVersion{0}; #endif }; diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 3edb27ca..fbdb8d8f 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -66,8 +66,8 @@ bool VerifyBeginRenderPassAttribs(const BeginRenderPassAttribs& Attribs); bool VerifyStateTransitionDesc(const IRenderDevice* pDevice, const StateTransitionDesc& Barrier); bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs); -bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs); -bool VerifyCopyBLASAttribs(const CopyBLASAttribs& Attribs); +bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs, Uint32 PrevInstanceCount); +bool VerifyCopyBLASAttribs(const IRenderDevice* pDevice, const CopyBLASAttribs& Attribs); bool VerifyCopyTLASAttribs(const CopyTLASAttribs& Attribs); bool VerifyWriteBLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteBLASCompactedSizeAttribs& Attribs); bool VerifyWriteTLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteTLASCompactedSizeAttribs& Attribs); @@ -1482,17 +1482,10 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>::BuildTLAS(const Bui return false; } - if (!VerifyBuildTLASAttribs(Attribs)) - return false; + const Uint32 InstCount = Attribs.pTLAS ? ValidatedCast<TopLevelASType>(Attribs.pTLAS)->GetInstanceCount() : 0; - for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) - { - if (!ValidatedCast<BottomLevelASType>(Attribs.pInstances[i].pBLAS)->ValidateContent()) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances[", i, "].pBLAS is not valid"); - return false; - } - } + if (!VerifyBuildTLASAttribs(Attribs, InstCount)) + return false; #endif return true; @@ -1514,14 +1507,8 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>::CopyBLAS(const Copy return false; } - if (!VerifyCopyBLASAttribs(Attribs)) + if (!VerifyCopyBLASAttribs(m_pDevice, Attribs)) return false; - - if (!ValidatedCast<BottomLevelASType>(Attribs.pSrc)->ValidateContent()) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: pSrc acceleration structure is not valid"); - return false; - } #endif return true; diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index 3f92416d..829437d4 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -205,15 +205,6 @@ public: return m_pRayTracingPipelineData->Desc; } - virtual Uint32 DILIGENT_CALL_TYPE GetShaderGroupCount() const override final - { - VERIFY_EXPR(this->m_Desc.IsRayTracingPipeline()); - VERIFY_EXPR(m_pRayTracingPipelineData != nullptr); - return static_cast<Uint32>(m_pRayTracingPipelineData->NameToGroupIndex.size()); - } - - static constexpr Uint32 InvalidShaderGroupIndex = ~0u; - virtual Uint32 DILIGENT_CALL_TYPE GetShaderGroupIndex(const char* Name) const override final { VERIFY_EXPR(Name != nullptr && Name[0] != '\0'); @@ -225,10 +216,10 @@ public: return iter->second; UNEXPECTED("Can't find shader group with specified name"); - return InvalidShaderGroupIndex; + return INVALID_INDEX; } - inline void CopyShaderHandle(const char* Name, void* pData, Uint32 DataSize) const + inline void CopyShaderHandle(const char* Name, void* pData, size_t DataSize) const { VERIFY_EXPR(this->m_Desc.IsRayTracingPipeline()); VERIFY_EXPR(m_pRayTracingPipelineData != nullptr); diff --git a/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp index ff6d7e95..41983aa8 100644 --- a/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp @@ -33,6 +33,7 @@ #include <unordered_map> #include "ShaderBindingTable.h" +#include "TopLevelASBase.hpp" #include "DeviceObjectBase.hpp" #include "RenderDeviceBase.hpp" #include "StringPool.hpp" @@ -50,7 +51,7 @@ void ValidateShaderBindingTableDesc(const ShaderBindingTableDesc& Desc, Uint32 S /// (Diligent::IShaderBindingTableD3D12 or Diligent::IShaderBindingTableVk). /// \tparam RenderDeviceImplType - type of the render device implementation /// (Diligent::RenderDeviceD3D12Impl or Diligent::RenderDeviceVkImpl) -template <class BaseInterface, class PipelineStateImplType, class RenderDeviceImplType> +template <class BaseInterface, class PipelineStateImplType, class TopLevelASImplType, class RenderDeviceImplType> class ShaderBindingTableBase : public DeviceObjectBase<BaseInterface, RenderDeviceImplType, ShaderBindingTableDesc> { public: @@ -81,203 +82,312 @@ public: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderBindingTable, TDeviceObjectBase) - void DILIGENT_CALL_TYPE Reset(const ShaderBindingTableDesc& Desc) override final + + void DILIGENT_CALL_TYPE Reset(IPipelineState* pPSO) override final { +#ifdef DILIGENT_DEVELOPMENT + this->m_DbgHitGroupBindings.clear(); +#endif this->m_RayGenShaderRecord.clear(); this->m_MissShadersRecord.clear(); this->m_CallableShadersRecord.clear(); this->m_HitGroupsRecord.clear(); - this->m_Changed = true; - this->m_pPSO = nullptr; - const auto* Name = this->m_Desc.Name; // Store original name - this->m_Desc = {}; + this->m_Changed = true; + this->m_pPSO = nullptr; + + this->m_Desc.pPSO = pPSO; const auto& DeviceProps = this->m_pDevice->GetProperties(); try { - ValidateShaderBindingTableDesc(Desc, DeviceProps.ShaderGroupHandleSize, DeviceProps.MaxShaderRecordStride); + ValidateShaderBindingTableDesc(this->m_Desc, DeviceProps.ShaderGroupHandleSize, DeviceProps.MaxShaderRecordStride); } catch (const std::runtime_error&) { return; } - this->m_Desc = Desc; - this->m_Desc.Name = Name; // Restore original name this->m_pPSO = ValidatedCast<PipelineStateImplType>(this->m_Desc.pPSO); this->m_ShaderRecordSize = this->m_pPSO->GetRayTracingPipelineDesc().ShaderRecordSize; this->m_ShaderRecordStride = this->m_ShaderRecordSize + DeviceProps.ShaderGroupHandleSize; } - void DILIGENT_CALL_TYPE BindRayGenShader(const char* ShaderGroupName, const void* Data, Uint32 DataSize) override final + + void DILIGENT_CALL_TYPE ResetHitGroups() override final { - VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); - VERIFY_EXPR((Data == nullptr) || (DataSize == this->m_ShaderRecordSize)); +#ifdef DILIGENT_DEVELOPMENT + this->m_DbgHitGroupBindings.clear(); +#endif + this->m_HitGroupsRecord.clear(); + this->m_Changed = true; + } + + + void DILIGENT_CALL_TYPE BindAll(const BindAllAttribs& Attribs) override final + { + // AZ TODO + } + + + void DILIGENT_CALL_TYPE BindRayGenShader(const char* pShaderGroupName, const void* pData, Uint32 DataSize) override final + { + VERIFY_EXPR((pData == nullptr) == (DataSize == 0)); + VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize)); this->m_RayGenShaderRecord.resize(this->m_ShaderRecordStride, Uint8{EmptyElem}); - this->m_pPSO->CopyShaderHandle(ShaderGroupName, this->m_RayGenShaderRecord.data(), this->m_ShaderRecordStride); + this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_RayGenShaderRecord.data(), this->m_ShaderRecordStride); const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize; - std::memcpy(this->m_RayGenShaderRecord.data() + GroupSize, Data, DataSize); + std::memcpy(this->m_RayGenShaderRecord.data() + GroupSize, pData, DataSize); this->m_Changed = true; } - void DILIGENT_CALL_TYPE BindMissShader(const char* ShaderGroupName, Uint32 MissIndex, const void* Data, Uint32 DataSize) override final + + void DILIGENT_CALL_TYPE BindMissShader(const char* pShaderGroupName, Uint32 MissIndex, const void* pData, Uint32 DataSize) override final { - VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); - VERIFY_EXPR((Data == nullptr) || (DataSize == this->m_ShaderRecordSize)); + VERIFY_EXPR((pData == nullptr) == (DataSize == 0)); + VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize)); const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize; - const Uint32 Offset = MissIndex * this->m_ShaderRecordStride; - this->m_MissShadersRecord.resize(std::max(this->m_MissShadersRecord.size(), size_t{Offset} + size_t{this->m_ShaderRecordStride}), Uint8{EmptyElem}); + const size_t Stride = this->m_ShaderRecordStride; + const size_t Offset = MissIndex * Stride; + this->m_MissShadersRecord.resize(std::max(this->m_MissShadersRecord.size(), Offset + Stride), Uint8{EmptyElem}); - 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_pPSO->CopyShaderHandle(pShaderGroupName, this->m_MissShadersRecord.data() + Offset, Stride); + std::memcpy(this->m_MissShadersRecord.data() + Offset + GroupSize, pData, DataSize); this->m_Changed = true; } + void DILIGENT_CALL_TYPE BindHitGroup(ITopLevelAS* pTLAS, - const char* InstanceName, - const char* GeometryName, + const char* pInstanceName, + const char* pGeometryName, Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data, + const char* pShaderGroupName, + const void* pData, Uint32 DataSize) override final { - VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); - VERIFY_EXPR((Data == nullptr) || (DataSize == this->m_ShaderRecordSize)); + VERIFY_EXPR((pData == nullptr) == (DataSize == 0)); + VERIFY_EXPR((pData == 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); - const auto Desc = pTLAS->GetInstanceDesc(InstanceName); - VERIFY_EXPR(Desc.pBLAS != nullptr); + auto* pTLASImpl = ValidatedCast<TopLevelASImplType>(pTLAS); + const auto Desc = pTLASImpl->GetInstanceDesc(pInstanceName); + + VERIFY_EXPR(pTLASImpl->GetBindingMode() == SHADER_BINDING_MODE_PER_GEOMETRY); + VERIFY_EXPR(RayOffsetInHitGroupIndex < pTLASImpl->GetHitShadersPerInstance()); + VERIFY_EXPR(Desc.ContributionToHitGroupIndex != INVALID_INDEX); + + if (Desc.pBLAS == nullptr) + return; // this is disabled instance const Uint32 InstanceIndex = Desc.ContributionToHitGroupIndex; - const Uint32 GeometryIndex = Desc.pBLAS->GetGeometryIndex(GeometryName); - VERIFY_EXPR(GeometryIndex != ~0u); - const Uint32 Index = InstanceIndex + GeometryIndex * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; - const Uint32 Offset = Index * this->m_ShaderRecordStride; + const Uint32 GeometryIndex = Desc.pBLAS->GetGeometryIndex(pGeometryName); + VERIFY_EXPR(GeometryIndex != INVALID_INDEX); + + const Uint32 Index = InstanceIndex + GeometryIndex * pTLASImpl->GetHitShadersPerInstance() + RayOffsetInHitGroupIndex; + const size_t Stride = this->m_ShaderRecordStride; const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize; + const size_t Offset = Index * Stride; - this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), size_t{Offset} + size_t{this->m_ShaderRecordStride}), Uint8{EmptyElem}); + this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), Offset + Stride), Uint8{EmptyElem}); - 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_pPSO->CopyShaderHandle(pShaderGroupName, this->m_HitGroupsRecord.data() + Offset, Stride); + std::memcpy(this->m_HitGroupsRecord.data() + Offset + GroupSize, pData, DataSize); this->m_Changed = true; + +#ifdef DILIGENT_DEVELOPMENT + OnBindHitGroup(pTLASImpl, Index); +#endif } + void DILIGENT_CALL_TYPE BindHitGroups(ITopLevelAS* pTLAS, - const char* InstanceName, + const char* pInstanceName, Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data, + const char* pShaderGroupName, + const void* pData, Uint32 DataSize) override final { - VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); + VERIFY_EXPR((pData == nullptr) == (DataSize == 0)); VERIFY_EXPR(pTLAS != nullptr); - VERIFY_EXPR(RayOffsetInHitGroupIndex < this->m_Desc.HitShadersPerInstance); - VERIFY_EXPR(pTLAS->GetDesc().BindingMode == SHADER_BINDING_MODE_PER_GEOMETRY || - pTLAS->GetDesc().BindingMode == SHADER_BINDING_MODE_PER_INSTANCE); - const auto Desc = pTLAS->GetInstanceDesc(InstanceName); - VERIFY_EXPR(Desc.pBLAS != nullptr); + auto* pTLASImpl = ValidatedCast<TopLevelASImplType>(pTLAS); + const auto Desc = pTLASImpl->GetInstanceDesc(pInstanceName); + + VERIFY_EXPR(pTLASImpl->GetBindingMode() == SHADER_BINDING_MODE_PER_GEOMETRY || + pTLASImpl->GetBindingMode() == SHADER_BINDING_MODE_PER_INSTANCE); + VERIFY_EXPR(RayOffsetInHitGroupIndex < pTLASImpl->GetHitShadersPerInstance()); + VERIFY_EXPR(Desc.ContributionToHitGroupIndex != INVALID_INDEX); const Uint32 InstanceIndex = Desc.ContributionToHitGroupIndex; - const auto& GeometryDesc = Desc.pBLAS->GetDesc(); Uint32 GeometryCount = 0; - switch (pTLAS->GetDesc().BindingMode) + switch (pTLASImpl->GetBindingMode()) { // clang-format off - case SHADER_BINDING_MODE_PER_GEOMETRY: GeometryCount = GeometryDesc.BoxCount + GeometryDesc.TriangleCount; break; - case SHADER_BINDING_MODE_PER_INSTANCE: GeometryCount = 1; break; + case SHADER_BINDING_MODE_PER_GEOMETRY: GeometryCount = Desc.pBLAS ? Desc.pBLAS->GetActualGeometryCount() : 0; 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)); + VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize * GeometryCount)); - const Uint32 BeginIndex = InstanceIndex + 0 * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; - const Uint32 EndIndex = InstanceIndex + GeometryCount * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; + const Uint32 BeginIndex = InstanceIndex + RayOffsetInHitGroupIndex; + const size_t EndIndex = InstanceIndex + GeometryCount * pTLASImpl->GetHitShadersPerInstance() + RayOffsetInHitGroupIndex; const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize; - const auto* DataPtr = static_cast<const Uint8*>(Data); + const size_t Stride = this->m_ShaderRecordStride; + const auto* DataPtr = static_cast<const Uint8*>(pData); - this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), size_t{EndIndex} * size_t{this->m_ShaderRecordStride}), Uint8{EmptyElem}); + this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), EndIndex * Stride), Uint8{EmptyElem}); for (Uint32 i = 0; i < GeometryCount; ++i) { - Uint32 Offset = (BeginIndex + i) * this->m_ShaderRecordStride; - this->m_pPSO->CopyShaderHandle(ShaderGroupName, this->m_HitGroupsRecord.data() + Offset, this->m_ShaderRecordStride); + size_t Offset = (BeginIndex + i) * Stride; + this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_HitGroupsRecord.data() + Offset, Stride); std::memcpy(this->m_HitGroupsRecord.data() + Offset + GroupSize, DataPtr, this->m_ShaderRecordSize); DataPtr += this->m_ShaderRecordSize; + +#ifdef DILIGENT_DEVELOPMENT + OnBindHitGroup(pTLASImpl, BeginIndex + i); +#endif } this->m_Changed = true; } - void DILIGENT_CALL_TYPE BindCallableShader(const char* ShaderGroupName, + + void DILIGENT_CALL_TYPE BindHitGroupForAll(ITopLevelAS* pTLAS, + Uint32 RayOffsetInHitGroupIndex, + const char* pShaderGroupName, + const void* pData, + Uint32 DataSize) override final + { + VERIFY_EXPR((pData == nullptr) == (DataSize == 0)); + VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize)); + VERIFY_EXPR(pTLAS != nullptr); + + auto* pTLASImpl = ValidatedCast<TopLevelASImplType>(pTLAS); + VERIFY_EXPR(pTLASImpl->GetBindingMode() == SHADER_BINDING_MODE_PER_GEOMETRY || + pTLASImpl->GetBindingMode() == SHADER_BINDING_MODE_PER_INSTANCE || + pTLASImpl->GetBindingMode() == SHADER_BINDING_MODE_PER_ACCEL_STRUCT); + VERIFY_EXPR(RayOffsetInHitGroupIndex < pTLASImpl->GetHitShadersPerInstance()); + + Uint32 FirstContributionToHitGroupIndex, LastContributionToHitGroupIndex; + pTLASImpl->GetContributionToHitGroupIndex(FirstContributionToHitGroupIndex, LastContributionToHitGroupIndex); + + const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize; + const size_t Stride = this->m_ShaderRecordStride; + this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), (LastContributionToHitGroupIndex + 1) * Stride), Uint8{EmptyElem}); + this->m_Changed = true; + + for (Uint32 Index = FirstContributionToHitGroupIndex; Index <= LastContributionToHitGroupIndex; ++Index) + { + const size_t Offset = Index * Stride; + this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_HitGroupsRecord.data() + Offset, Stride); + std::memcpy(this->m_HitGroupsRecord.data() + Offset + GroupSize, pData, DataSize); + +#ifdef DILIGENT_DEVELOPMENT + OnBindHitGroup(pTLASImpl, Index); +#endif + } + } + + + void DILIGENT_CALL_TYPE BindCallableShader(const char* pShaderGroupName, Uint32 CallableIndex, - const void* Data, + const void* pData, Uint32 DataSize) override final { - VERIFY_EXPR((Data == nullptr) == (DataSize == 0)); - VERIFY_EXPR((Data == nullptr) || (DataSize == this->m_ShaderRecordSize)); + VERIFY_EXPR((pData == nullptr) == (DataSize == 0)); + VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize)); const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize; - const Uint32 Offset = CallableIndex * this->m_ShaderRecordStride; - this->m_CallableShadersRecord.resize(std::max(this->m_CallableShadersRecord.size(), size_t{Offset} + size_t{this->m_ShaderRecordStride}), Uint8{EmptyElem}); + const size_t Offset = CallableIndex * this->m_ShaderRecordStride; + this->m_CallableShadersRecord.resize(std::max(this->m_CallableShadersRecord.size(), Offset + this->m_ShaderRecordStride), Uint8{EmptyElem}); - 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_pPSO->CopyShaderHandle(pShaderGroupName, this->m_CallableShadersRecord.data() + Offset, this->m_ShaderRecordStride); + std::memcpy(this->m_CallableShadersRecord.data() + Offset + GroupSize, pData, DataSize); this->m_Changed = true; } - Bool DILIGENT_CALL_TYPE Verify() const override final + + Bool DILIGENT_CALL_TYPE Verify(SHADER_BINDING_VALIDATION_FLAGS Flags) const override final { - Uint32 ShCounter = 0; - Uint32 RecCounter = 0; const auto Stride = this->m_ShaderRecordStride; const auto ShSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize; - const auto FindPattern = [&ShCounter, &RecCounter, Stride, ShSize](const std::vector<Uint8>& Data, const char* Name) -> bool // + const auto FindPattern = [&](const std::vector<Uint8>& Data, const char* GroupName) -> bool // { for (size_t i = 0; i < Data.size(); i += Stride) { - Uint32 Count = 0; - for (size_t j = 0; j < ShSize; ++j) - Count += (Data[i + j] == EmptyElem); - - if (Count == ShSize) + if (Flags & SHADER_BINDING_VALIDATION_SHADER_ONLY) { - LOG_ERROR_MESSAGE("Shader binding table is not valid: shader in '", Name, "'(", i / Stride, ") is not bound"); - return false; + Uint32 Count = 0; + for (size_t j = 0; j < ShSize; ++j) + Count += (Data[i + j] == EmptyElem); + + if (Count == ShSize) + { + LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: shader in '", GroupName, "'(", i / Stride, ") is not bound"); + return false; + } } - Count = 0; - for (size_t j = ShSize; j < Stride; ++j) - Count += (Data[i + j] == EmptyElem); - - if (Count > Stride - ShSize) - LOG_WARNING_MESSAGE("Shader binding table is not valid: shader record data in '", Name, "'(", i / Stride, ") is not initialized"); + if ((Flags & SHADER_BINDING_VALIDATION_SHADER_RECORD) && this->m_ShaderRecordSize > 0) + { + Uint32 Count = 0; + for (size_t j = ShSize; j < Stride; ++j) + Count += (Data[i + j] == EmptyElem); + + // shader record data may not used in shader + if (Count == Stride - ShSize) + { + LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: shader record data in '", GroupName, "'(", i / Stride, ") is not initialized"); + return false; + } + } } return true; }; if (m_RayGenShaderRecord.empty()) { - LOG_ERROR_MESSAGE("Shader binding table is not valid: ray generation shader is not bound"); + LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: ray generation shader is not bound"); return false; } - if (!FindPattern(m_RayGenShaderRecord, "ray generation") || - !FindPattern(m_MissShadersRecord, "miss") || - !FindPattern(m_CallableShadersRecord, "callable") || - !FindPattern(m_HitGroupsRecord, "hit groups")) - return false; - - return true; +#ifdef DILIGENT_DEVELOPMENT + if (Flags & SHADER_BINDING_VALIDATION_TLAS) + { + for (size_t i = 0; i < m_DbgHitGroupBindings.size(); ++i) + { + auto& Binding = m_DbgHitGroupBindings[i]; + auto pTLAS = Binding.pTLAS.Lock(); + if (!pTLAS) + { + LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: TLAS that was used to bind hit group at index (", i, ") was deleted"); + return false; + } + if (pTLAS->GetVersion() != Binding.Version) + { + LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: TLAS that was used to bind hit group at index '(", i, + ") with name '", pTLAS->GetDesc().Name, " was changed and no longer compatible with SBT"); + return false; + } + } + } +#endif + + bool valid = true; + valid = valid && FindPattern(m_RayGenShaderRecord, "ray generation"); + valid = valid && FindPattern(m_MissShadersRecord, "miss"); + valid = valid && FindPattern(m_CallableShadersRecord, "callable"); + valid = valid && FindPattern(m_HitGroupsRecord, "hit groups"); + return valid; } + struct BindingTable { const void* pData = nullptr; @@ -362,6 +472,7 @@ public: this->m_Changed = false; } + protected: std::vector<Uint8> m_RayGenShaderRecord; std::vector<Uint8> m_MissShadersRecord; @@ -376,6 +487,25 @@ protected: bool m_Changed = true; static constexpr Uint8 EmptyElem = 0xA7; + +private: +#ifdef DILIGENT_DEVELOPMENT + struct HitGroupBinding + { + RefCntWeakPtr<TopLevelASImplType> pTLAS; + Uint32 Version = ~0u; + }; + mutable std::vector<HitGroupBinding> m_DbgHitGroupBindings; + + void OnBindHitGroup(TopLevelASImplType* pTLAS, Uint32 Index) + { + this->m_DbgHitGroupBindings.resize(Index + 1); + + auto& Binding = this->m_DbgHitGroupBindings[Index]; + Binding.pTLAS = pTLAS; + Binding.Version = pTLAS->GetVersion(); + } +#endif }; } // namespace Diligent diff --git a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp index 9fef2399..fa322e30 100644 --- a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp @@ -364,6 +364,58 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs, return BindingOK; } +template <typename ResourceAttribsType> +bool VerifyTLASResourceBinding(const ResourceAttribsType& Attribs, + SHADER_RESOURCE_VARIABLE_TYPE VarType, + Uint32 ArrayIndex, + const ITopLevelAS* pTLAS, + const IDeviceObject* pCachedAS, + const char* ShaderName = nullptr) +{ + if (!pTLAS) + { + std::stringstream ss; + ss << "Failed to bind resource '" << pTLAS->GetDesc().Name << "' to variable '" << Attribs.GetPrintName(ArrayIndex) << '\''; + if (ShaderName != nullptr) + { + ss << " in shader '" << ShaderName << '\''; + } + ss << ". Invalid resource type: TLAS is expected."; + LOG_ERROR_MESSAGE(ss.str()); + return false; + } + + bool BindingOK = true; + + if (VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && pCachedAS != nullptr && pCachedAS != pTLAS) + { + const auto* VarTypeStr = GetShaderVariableTypeLiteralName(VarType); + + std::stringstream ss; + ss << "Non-null resource '" << pCachedAS->GetDesc().Name << "' is already bound to " << VarTypeStr + << " shader variable '" << Attribs.GetPrintName(ArrayIndex) << '\''; + if (ShaderName != nullptr) + { + ss << " in shader '" << ShaderName << '\''; + } + ss << ". Attempting to bind "; + if (pTLAS) + { + ss << "another resource ('" << pTLAS->GetDesc().Name << "')"; + } + else + { + ss << "null"; + } + ss << " is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic."; + LOG_ERROR_MESSAGE(ss.str()); + + BindingOK = false; + } + + return BindingOK; +} + inline void VerifyAndCorrectSetArrayArguments(const char* Name, Uint32 ArraySize, Uint32& FirstElement, Uint32& NumElements) { if (FirstElement >= ArraySize) diff --git a/Graphics/GraphicsEngine/include/TopLevelASBase.hpp b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp index efba30c7..bfc89dd2 100644 --- a/Graphics/GraphicsEngine/include/TopLevelASBase.hpp +++ b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp @@ -31,8 +31,10 @@ /// Implementation of the Diligent::TopLevelASBase template class #include <unordered_map> +#include <atomic> #include "TopLevelAS.h" +#include "BottomLevelASBase.hpp" #include "DeviceObjectBase.hpp" #include "RenderDeviceBase.hpp" #include "StringPool.hpp" @@ -53,6 +55,17 @@ void ValidateTopLevelASDesc(const TopLevelASDesc& Desc) noexcept(false); template <class BaseInterface, class BottomLevelASType, class RenderDeviceImplType> class TopLevelASBase : public DeviceObjectBase<BaseInterface, RenderDeviceImplType, TopLevelASDesc> { +private: + struct InstanceDesc + { + Uint32 ContributionToHitGroupIndex = 0; + Uint32 InstanceIndex = 0; + RefCntAutoPtr<BottomLevelASType> pBLAS; +#ifdef DILIGENT_DEVELOPMENT + Uint32 Version = 0; +#endif + }; + public: using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, TopLevelASDesc>; @@ -76,14 +89,16 @@ public: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelAS, TDeviceObjectBase) - void SetInstanceData(const TLASBuildInstanceData* pInstances, Uint32 InstanceCount, Uint32 HitShadersPerInstance) noexcept + bool SetInstanceData(const TLASBuildInstanceData* pInstances, + const Uint32 InstanceCount, + const Uint32 BaseContributionToHitGroupIndex, + const Uint32 HitShadersPerInstance, + const SHADER_BINDING_MODE BindingMode) noexcept { try { ClearInstanceData(); - this->m_HitShadersPerInstance = HitShadersPerInstance; - size_t StringPoolSize = 0; for (Uint32 i = 0; i < InstanceCount; ++i) { @@ -93,56 +108,113 @@ public: this->m_StringPool.Reserve(StringPoolSize, GetRawAllocator()); - Uint32 InstanceOffset = 0; + Uint32 InstanceOffset = BaseContributionToHitGroupIndex; for (Uint32 i = 0; i < InstanceCount; ++i) { - auto& inst = pInstances[i]; - const char* NameCopy = this->m_StringPool.CopyString(inst.InstanceName); + const auto& Inst = pInstances[i]; + const char* NameCopy = this->m_StringPool.CopyString(Inst.InstanceName); InstanceDesc Desc = {}; - Desc.ContributionToHitGroupIndex = inst.ContributionToHitGroupIndex; - Desc.pBLAS = ValidatedCast<BottomLevelASType>(inst.pBLAS); + Desc.pBLAS = ValidatedCast<BottomLevelASType>(Inst.pBLAS); + Desc.ContributionToHitGroupIndex = Inst.ContributionToHitGroupIndex; + Desc.InstanceIndex = i; + CalculateHitGroupIndex(Desc, InstanceOffset, HitShadersPerInstance, BindingMode); #ifdef DILIGENT_DEVELOPMENT - Desc.Version = Desc.pBLAS->GetVersion(); + Desc.Version = Desc.pBLAS ? Desc.pBLAS->GetVersion() : ~0u; #endif - - if (Desc.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) - { - Desc.ContributionToHitGroupIndex = InstanceOffset; - auto& BLASDesc = Desc.pBLAS->GetDesc(); - 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 = 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); + + this->m_HitShadersPerInstance = HitShadersPerInstance; + this->m_FirstContributionToHitGroupIndex = BaseContributionToHitGroupIndex; + this->m_LastContributionToHitGroupIndex = InstanceOffset; + this->m_BindingMode = BindingMode; + +#ifdef DILIGENT_DEVELOPMENT + this->m_DbgVersion.fetch_add(1); +#endif + return true; } catch (...) { +#ifdef DILIGENT_DEVELOPMENT + this->m_DbgVersion.fetch_add(1); +#endif ClearInstanceData(); + return false; } } + bool UpdateInstances(const TLASBuildInstanceData* pInstances, + const Uint32 InstanceCount, + const Uint32 BaseContributionToHitGroupIndex, + const Uint32 HitShadersPerInstance, + const SHADER_BINDING_MODE BindingMode) noexcept + { +#ifdef DILIGENT_DEVELOPMENT + bool Changed = false; +#endif + Uint32 InstanceOffset = BaseContributionToHitGroupIndex; + + for (Uint32 i = 0; i < InstanceCount; ++i) + { + const auto& Inst = pInstances[i]; + auto Iter = this->m_Instances.find(Inst.InstanceName); + + if (Iter == this->m_Instances.end()) + { + UNEXPECTED("Failed to find instance with name '", Inst.InstanceName, "' in instances from previous build"); + return false; + } + + auto& Desc = Iter->second; + const auto PrevIndex = Desc.ContributionToHitGroupIndex; + const auto* pPrevBLAS = Desc.pBLAS.template RawPtr<IBottomLevelAS>(); + + Desc.pBLAS = ValidatedCast<BottomLevelASType>(Inst.pBLAS); + Desc.ContributionToHitGroupIndex = Inst.ContributionToHitGroupIndex; + //Desc.InstanceIndex = i; // keep Desc.InstanceIndex unmodified + CalculateHitGroupIndex(Desc, InstanceOffset, HitShadersPerInstance, BindingMode); + +#ifdef DILIGENT_DEVELOPMENT + Changed = Changed || (pPrevBLAS != Inst.pBLAS); + Changed = Changed || (Desc.pBLAS ? Desc.Version != Desc.pBLAS->GetVersion() : false); + Changed = Changed || (PrevIndex != Desc.ContributionToHitGroupIndex); + Desc.Version = Desc.pBLAS ? Desc.pBLAS->GetVersion() : ~0u; +#endif + } + +#ifdef DILIGENT_DEVELOPMENT + Changed = Changed || (this->m_HitShadersPerInstance != HitShadersPerInstance); + Changed = Changed || (this->m_FirstContributionToHitGroupIndex != BaseContributionToHitGroupIndex); + Changed = Changed || (this->m_LastContributionToHitGroupIndex != InstanceOffset); + Changed = Changed || (this->m_BindingMode != BindingMode); + if (Changed) + this->m_DbgVersion.fetch_add(1); +#endif + this->m_HitShadersPerInstance = HitShadersPerInstance; + this->m_FirstContributionToHitGroupIndex = BaseContributionToHitGroupIndex; + this->m_LastContributionToHitGroupIndex = InstanceOffset; + this->m_BindingMode = BindingMode; + + return true; + } + void CopyInstancceData(const TopLevelASBase& Src) noexcept { ClearInstanceData(); this->m_StringPool.Reserve(Src.m_StringPool.GetReservedSize(), GetRawAllocator()); - this->m_HitShadersPerInstance = Src.m_HitShadersPerInstance; - this->m_Desc.BindingMode = Src.m_Desc.BindingMode; + this->m_HitShadersPerInstance = Src.m_HitShadersPerInstance; + this->m_FirstContributionToHitGroupIndex = Src.m_FirstContributionToHitGroupIndex; + this->m_LastContributionToHitGroupIndex = Src.m_LastContributionToHitGroupIndex; + this->m_BindingMode = Src.m_BindingMode; for (auto& SrcInst : Src.m_Instances) { @@ -151,6 +223,25 @@ public: } VERIFY_EXPR(this->m_StringPool.GetRemainingSize() == 0); + +#ifdef DILIGENT_DEVELOPMENT + this->m_DbgVersion.fetch_add(1); +#endif + } + + Uint32 GetInstanceCount() const + { + return static_cast<Uint32>(this->m_Instances.size()); + } + + Uint32 GetHitShadersPerInstance() const + { + return this->m_HitShadersPerInstance; + } + + SHADER_BINDING_MODE GetBindingMode() const + { + return this->m_BindingMode; } virtual TLASInstanceDesc DILIGENT_CALL_TYPE GetInstanceDesc(const char* Name) const override final @@ -159,23 +250,36 @@ public: TLASInstanceDesc Result = {}; - auto iter = this->m_Instances.find(Name); - if (iter != this->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.template RawPtr<IBottomLevelAS>(); + const auto& Inst = Iter->second; + Result.ContributionToHitGroupIndex = Inst.ContributionToHitGroupIndex; + Result.InstanceIndex = Inst.InstanceIndex; + Result.pBLAS = Inst.pBLAS.template RawPtr<IBottomLevelAS>(); } else { - UNEXPECTED("Can't find instance with the specified name ('", Name, "')"); + Result.ContributionToHitGroupIndex = INVALID_INDEX; + Result.InstanceIndex = INVALID_INDEX; + LOG_ERROR_MESSAGE("Can't find instance with the specified name ('", Name, "')"); } return Result; } + virtual void DILIGENT_CALL_TYPE GetContributionToHitGroupIndex(Uint32& FirstContributionToHitGroupIndex, + Uint32& LastContributionToHitGroupIndex) const override final + { + FirstContributionToHitGroupIndex = this->m_FirstContributionToHitGroupIndex; + LastContributionToHitGroupIndex = this->m_LastContributionToHitGroupIndex; + + VERIFY_EXPR(FirstContributionToHitGroupIndex <= LastContributionToHitGroupIndex); + } + virtual void DILIGENT_CALL_TYPE SetState(RESOURCE_STATE State) override final { - VERIFY(State == RESOURCE_STATE_BUILD_AS_READ || State == RESOURCE_STATE_BUILD_AS_WRITE || State == RESOURCE_STATE_RAY_TRACING, + VERIFY(State == RESOURCE_STATE_UNKNOWN || State == RESOURCE_STATE_BUILD_AS_READ || State == RESOURCE_STATE_BUILD_AS_WRITE || State == RESOURCE_STATE_RAY_TRACING, "Unsupported state for top-level acceleration structure"); this->m_State = State; } @@ -186,9 +290,9 @@ public: } /// Implementation of ITopLevelAS::GetScratchBufferSizes(). - virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override + virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override final { - return m_ScratchSize; + return this->m_ScratchSize; } bool IsInKnownState() const @@ -208,66 +312,97 @@ public: { bool result = true; - if (m_Instances.empty()) + if (this->m_Instances.empty()) { LOG_ERROR_MESSAGE("TLAS with name ('", this->m_Desc.Name, "') doesn't have instances, use IDeviceContext::BuildTLAS() or IDeviceContext::CopyTLAS() to initialize TLAS content"); result = false; } // Validate instances - for (const auto& NameAndInst : m_Instances) + for (const auto& NameAndInst : this->m_Instances) { - const InstanceDesc& Inst = NameAndInst.second; - const BottomLevelASDesc& Desc = Inst.pBLAS->GetDesc(); + const InstanceDesc& Inst = NameAndInst.second; + + if (Inst.pBLAS == nullptr) + continue; if (Inst.Version != Inst.pBLAS->GetVersion()) { - LOG_ERROR_MESSAGE("Instance with name ('", NameAndInst.first.GetStr(), "') has BLAS with name ('", Desc.Name, "') that was changed after TLAS build, you must rebuild TLAS"); + LOG_ERROR_MESSAGE("Instance with name ('", NameAndInst.first.GetStr(), "') has BLAS with name ('", Inst.pBLAS->GetDesc().Name, + "') that was changed after TLAS build, you must rebuild TLAS"); result = false; } - if (Inst.pBLAS->GetState() != RESOURCE_STATE_BUILD_AS_READ) + if (Inst.pBLAS->IsInKnownState() && Inst.pBLAS->GetState() != RESOURCE_STATE_BUILD_AS_READ) { - LOG_ERROR_MESSAGE("Instance with name ('", NameAndInst.first.GetStr(), "') has BLAS with name ('", Desc.Name, "') that must be in BUILD_AS_READ state, but current state is ", + LOG_ERROR_MESSAGE("Instance with name ('", NameAndInst.first.GetStr(), "') has BLAS with name ('", Inst.pBLAS->GetDesc().Name, + "') that must be in BUILD_AS_READ state, but current state is ", GetResourceStateFlagString(Inst.pBLAS->GetState())); result = false; } - - if (!Inst.pBLAS->ValidateContent()) - { - LOG_ERROR_MESSAGE("Instance with name ('", NameAndInst.first.GetStr(), "') has BLAS with name ('", Desc.Name, "') that is not valid"); - result = false; - } } return result; } -#endif + + Uint32 GetVersion() const + { + return this->m_DbgVersion.load(); + } +#endif // DILIGENT_DEVELOPMENT private: void ClearInstanceData() { this->m_Instances.clear(); this->m_StringPool.Clear(); + + this->m_BindingMode = SHADER_BINDING_MODE_LAST; + this->m_HitShadersPerInstance = 0; + this->m_FirstContributionToHitGroupIndex = INVALID_INDEX; + this->m_LastContributionToHitGroupIndex = INVALID_INDEX; } -protected: - RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN; - Uint32 m_HitShadersPerInstance = 0; + static void CalculateHitGroupIndex(InstanceDesc& Desc, Uint32& InstanceOffset, const Uint32 HitShadersPerInstance, const SHADER_BINDING_MODE BindingMode) + { + static_assert(SHADER_BINDING_MODE_LAST == SHADER_BINDING_USER_DEFINED, "Please update the switch below to handle the new shader binding mode"); - ScratchBufferSizes m_ScratchSize; + if (Desc.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) + { + Desc.ContributionToHitGroupIndex = InstanceOffset; + switch (BindingMode) + { + // clang-format off + case SHADER_BINDING_MODE_PER_GEOMETRY: InstanceOffset += Desc.pBLAS ? Desc.pBLAS->GetActualGeometryCount() * HitShadersPerInstance : 0; break; + case SHADER_BINDING_MODE_PER_INSTANCE: InstanceOffset += HitShadersPerInstance; break; + case SHADER_BINDING_MODE_PER_ACCEL_STRUCT: /* InstanceOffset is a constant */ 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 + } + } + else + { + VERIFY(BindingMode == SHADER_BINDING_USER_DEFINED, "BindingMode must be SHADER_BINDING_USER_DEFINED"); + } - StringPool m_StringPool; + constexpr Uint32 MaxIndex = (1u << 24); + VERIFY(Desc.ContributionToHitGroupIndex < MaxIndex, "ContributionToHitGroupIndex must be less than ", MaxIndex); + } - struct InstanceDesc - { - Uint32 ContributionToHitGroupIndex = 0; - RefCntAutoPtr<BottomLevelASType> pBLAS; +protected: + RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN; + SHADER_BINDING_MODE m_BindingMode = SHADER_BINDING_MODE_LAST; + Uint32 m_HitShadersPerInstance = 0; + Uint32 m_FirstContributionToHitGroupIndex = INVALID_INDEX; + Uint32 m_LastContributionToHitGroupIndex = INVALID_INDEX; + ScratchBufferSizes m_ScratchSize; + + std::unordered_map<HashMapStringKey, InstanceDesc, HashMapStringKey::Hasher> m_Instances; + StringPool m_StringPool; #ifdef DILIGENT_DEVELOPMENT - Uint32 Version = 0; + std::atomic<Uint32> m_DbgVersion{0}; #endif - }; - std::unordered_map<HashMapStringKey, InstanceDesc, HashMapStringKey::Hasher> m_Instances; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngine/interface/BottomLevelAS.h b/Graphics/GraphicsEngine/interface/BottomLevelAS.h index be9eb0c1..4aafefb9 100644 --- a/Graphics/GraphicsEngine/interface/BottomLevelAS.h +++ b/Graphics/GraphicsEngine/interface/BottomLevelAS.h @@ -44,6 +44,9 @@ static const INTERFACE_ID IID_BottomLevelAS = // clang-format off +static const Uint32 INVALID_INDEX = ~0u; + + /// Defines bottom level acceleration structure triangles description. /// Triangle geometry description. @@ -112,12 +115,15 @@ DILIGENT_TYPED_ENUM(RAYTRACING_BUILD_AS_FLAGS, Uint8) { RAYTRACING_BUILD_AS_NONE = 0, - /// AZ TODO: not supported yet + /// Indicates that the specified acceleration structure can be updated + /// via IDeviceContext::BuildBLAS() or IDeviceContext::BuildTLAS(). + /// With this flag acculeration structure may allocate more memory and take more time on build. RAYTRACING_BUILD_AS_ALLOW_UPDATE = 0x01, /// Indicates that the specified acceleration structure can act as the source for /// a copy acceleration structure command IDeviceContext::CopyBLAS() or IDeviceContext::CopyTLAS() /// with COPY_AS_MODE_COMPACT mode to produce a compacted acceleration structure. + /// With this flag acculeration structure may allocate more memory and take more time on build. RAYTRACING_BUILD_AS_ALLOW_COMPACTION = 0x02, /// Indicates that the given acceleration structure build should prioritize trace performance over build time. @@ -170,10 +176,15 @@ typedef struct BottomLevelASDesc BottomLevelASDesc; /// Defines the scratch buffer info for acceleration structure. struct ScratchBufferSizes { - /// Scratch buffer size for acceleration structure building. + /// Scratch buffer size for acceleration structure building, + /// see IDeviceContext::BuildBLAS(), IDeviceContext::BuildTLAS(). + /// May be zero if acceleration structure created with non-zero CompactedSize. Uint32 Build DEFAULT_INITIALIZER(0); - - /// AZ TODO: not supported yet + + /// Scratch buffer size for acceleration structure updating, + /// see IDeviceContext::BuildBLAS(), IDeviceContext::BuildTLAS(). + /// May be zero if acceleration structure created without RAYTRACING_BUILD_AS_ALLOW_UPDATE flag. + /// May be zero if acceleration structure created with non-zero CompactedSize. Uint32 Update DEFAULT_INITIALIZER(0); #if DILIGENT_CPP_INTERFACE @@ -182,7 +193,6 @@ struct ScratchBufferSizes }; typedef struct ScratchBufferSizes ScratchBufferSizes; -static const Uint32 InvalidGeometryIndex = ~0u; #define DILIGENT_INTERFACE_NAME IBottomLevelAS #include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" @@ -201,24 +211,48 @@ DILIGENT_BEGIN_INTERFACE(IBottomLevelAS, IDeviceObject) virtual const BottomLevelASDesc& DILIGENT_CALL_TYPE GetDesc() const override = 0; #endif + /// Returns the geometry description index in BottomLevelASDesc::pTriangles or BottomLevelASDesc::pBoxes. + + /// \param [in] Name - Geometry name that is specified in BLASTriangleDesc or BLASBoundingBoxDesc. + /// \return Geometry index or INVALID_INDEX if geometry does not exist. + /// + /// \note Access to the BLAS must be externally synchronized. + VIRTUAL Uint32 METHOD(GetGeometryDescIndex)(THIS_ + const char* Name) CONST PURE; + + /// Returns the geometry index that can be used in a shader binding table. /// \param [in] Name - Geometry name that is specified in BLASTriangleDesc or BLASBoundingBoxDesc. - /// \return Geometry index. + /// \return Geometry index or INVALID_INDEX if geometry does not exist. + /// + /// \note Access to the BLAS must be externally synchronized. VIRTUAL Uint32 METHOD(GetGeometryIndex)(THIS_ const char* Name) CONST PURE; + + /// Returns the geometry count that was used to build AS. + /// Same as BuildBLASAttribs::TriangleDataCount or BuildBLASAttribs::BoxDataCount. + + /// \return The number of geometries that was used to build AS. + /// + /// \note Access to the BLAS must be externally synchronized. + VIRTUAL Uint32 METHOD(GetActualGeometryCount)(THIS) CONST PURE; + + /// Returns the scratch buffer info for the current acceleration structure. /// \return ScratchBufferSizes object, see Diligent::ScratchBufferSizes. VIRTUAL ScratchBufferSizes METHOD(GetScratchBufferSizes)(THIS) CONST PURE; + /// Returns the native acceleration structure handle specific to the underlying graphics API /// \return pointer to ID3D12Resource interface, for D3D12 implementation\n - /// VkAccelerationStructureKHR handle, for Vulkan implementation + /// VkAccelerationStructure handle, for Vulkan implementation VIRTUAL void* METHOD(GetNativeHandle)(THIS) PURE; + /// Sets the acceleration structure usage state. /// \note This method does not perform state transition, but @@ -229,6 +263,7 @@ DILIGENT_BEGIN_INTERFACE(IBottomLevelAS, IDeviceObject) VIRTUAL void METHOD(SetState)(THIS_ RESOURCE_STATE State) PURE; + /// Returns the internal acceleration structure state VIRTUAL RESOURCE_STATE METHOD(GetState)(THIS) CONST PURE; }; @@ -240,11 +275,13 @@ DILIGENT_END_INTERFACE // clang-format off -# define IBottomLevelAS_GetGeometryIndex(This, ...) CALL_IFACE_METHOD(BottomLevelAS, GetGeometryIndex, This, __VA_ARGS__) -# define IBottomLevelAS_GetScratchBufferSizes(This) CALL_IFACE_METHOD(BottomLevelAS, GetScratchBufferSizes, This) -# define IBottomLevelAS_GetNativeHandle(This) CALL_IFACE_METHOD(BottomLevelAS, GetNativeHandle, This) -# define IBottomLevelAS_SetState(This, ...) CALL_IFACE_METHOD(BottomLevelAS, SetState, This, __VA_ARGS__) -# define IBottomLevelAS_GetState(This) CALL_IFACE_METHOD(BottomLevelAS, GetState, This) +# define IBottomLevelAS_GetGeometryDescIndex(This, ...) CALL_IFACE_METHOD(BottomLevelAS, GetGeometryDescIndex, This, __VA_ARGS__) +# define IBottomLevelAS_GetGeometryIndex(This, ...) CALL_IFACE_METHOD(BottomLevelAS, GetGeometryIndex, This, __VA_ARGS__) +# define IBottomLevelAS_GetActualGeometryCount(This) CALL_IFACE_METHOD(BottomLevelAS, GetActualGeometryCount, This) +# define IBottomLevelAS_GetScratchBufferSizes(This) CALL_IFACE_METHOD(BottomLevelAS, GetScratchBufferSizes, This) +# define IBottomLevelAS_GetNativeHandle(This) CALL_IFACE_METHOD(BottomLevelAS, GetNativeHandle, This) +# define IBottomLevelAS_SetState(This, ...) CALL_IFACE_METHOD(BottomLevelAS, SetState, This, __VA_ARGS__) +# define IBottomLevelAS_GetState(This) CALL_IFACE_METHOD(BottomLevelAS, GetState, This) // clang-format on diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index de0ce74f..83b67e70 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -805,10 +805,11 @@ struct BLASBuildTriangleData Uint32 VertexCount DEFAULT_INITIALIZER(0); /// The type of the vertex components. - /// This is an optional values. Must be undefined or same as in BLASTriangleDesc. + /// This is an optional value. Must be undefined or same as in BLASTriangleDesc. VALUE_TYPE VertexValueType DEFAULT_INITIALIZER(VT_UNDEFINED); - /// The number of vertex components + /// The number of vertex components. + /// This is an optional value. Must be undefined or same as in BLASTriangleDesc. Uint8 VertexComponentCount DEFAULT_INITIALIZER(0); /// The number of triangles. @@ -881,6 +882,7 @@ typedef struct BLASBuildBoundingBoxData BLASBuildBoundingBoxData; struct BuildBLASAttribs { /// Target bottom-level AS. + /// Access to the BLAS must be externally synchronized. IBottomLevelAS* pBLAS DEFAULT_INITIALIZER(nullptr); /// Bottom-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE). @@ -890,17 +892,27 @@ struct BuildBLASAttribs RESOURCE_STATE_TRANSITION_MODE GeometryTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); /// A pointer to an array of TriangleDataCount BLASBuildTriangleData structures that contains triangle geometry data. + /// If Update is true: + /// - Only vertex positions (in pVertexBuffer) and transformation (in pTransformBuffer) can be changed. + /// - All other content in BLASBuildTriangleData and buffers must be same as used to build BLAS. + /// - To disable geometry make all triangles inactive, see BLASBuildTriangleData::pVertexBuffer description. BLASBuildTriangleData const* pTriangleData DEFAULT_INITIALIZER(nullptr); /// The number of triangle grometries. /// Must be less than or equal to BottomLevelASDesc::TriangleCount. + /// If Update is true then count must be the same as used to build BLAS. Uint32 TriangleDataCount DEFAULT_INITIALIZER(0); /// A pointer to an array of BoxDataCount BLASBuildBoundingBoxData structures that contain AABB geometry data. + /// If Update is true: + /// - AABB coordinates (in pBoxBuffer) can be changed. + /// - All other content in BLASBuildBoundingBoxData must be same as used to build BLAS. + /// - To disable geometry make all AAABBs inactive, see BLASBuildBoundingBoxData::pBoxBuffer description. BLASBuildBoundingBoxData const* pBoxData DEFAULT_INITIALIZER(nullptr); /// The number of AABB geometries. /// Must be less than or equal to BottomLevelASDesc::BoxCount. + /// If Update is true then count must be the same as used to build BLAS. Uint32 BoxDataCount DEFAULT_INITIALIZER(0); /// The buffer that is used for acceleration structure building. @@ -914,6 +926,12 @@ struct BuildBLASAttribs /// Scratch buffer state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE). RESOURCE_STATE_TRANSITION_MODE ScratchBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); + /// if false then BLAS will be built from scratch. + /// If true then previous content of BLAS will be updated. + /// pBLAS must be created with RAYTRACING_BUILD_AS_ALLOW_UPDATE flag. + /// An update will be faster than building an acceleration structure from scratch. + Bool Update DEFAULT_INITIALIZER(False); + #if DILIGENT_CPP_INTERFACE BuildBLASAttribs() noexcept {} #endif @@ -921,10 +939,11 @@ struct BuildBLASAttribs typedef struct BuildBLASAttribs BuildBLASAttribs; -/// Can be used in TLASBuildInstanceData::ContributionToHitGroupIndex to calculate the index -/// depending on geometry count in TLASBuildInstanceData::pBLAS and shader binding mode in TopLevelASDesc::BindingMode. +/// Can be used to calculate the TLASBuildInstanceData::ContributionToHitGroupIndex depending on instance count, +/// geometry count in each instance (in TLASBuildInstanceData::pBLAS) and shader binding mode in BuildTLASAttribs::BindingMode. /// /// Example: +/// InstanceOffset = BaseContributionToHitGroupIndex; /// For each instance in TLAS /// if (Instance.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) /// Instance.ContributionToHitGroupIndex = InstanceOffset; @@ -981,6 +1000,8 @@ struct TLASBuildInstanceData const char* InstanceName DEFAULT_INITIALIZER(nullptr); /// Bottom-level AS that represents instance geometry. + /// Once built, TLAS will hold strong reference to pBLAS until next build or copy operation. + /// Access to the BLAS must be externally synchronized. IBottomLevelAS* pBLAS DEFAULT_INITIALIZER(nullptr); /// Instace to world transformation. @@ -994,12 +1015,11 @@ struct TLASBuildInstanceData RAYTRACING_INSTANCE_FLAGS Flags DEFAULT_INITIALIZER(RAYTRACING_INSTANCE_NONE); /// Visibility mask for the geometry, the instance may only be hit if rayMask & instance.Mask != 0. - /// (rayMask in GLSL is a cullMask argument of traceRayEXT(), rayMask in HLSL is an InstanceInclusionMask argument of TraceRay()). + /// ('rayMask' in GLSL is a 'cullMask' argument of traceRay(), 'rayMask' in HLSL is an 'InstanceInclusionMask' argument of TraceRay()). Uint8 Mask DEFAULT_INITIALIZER(0xFF); /// The index used to calculate the hit group location in the shader binding table. - /// Must be TLAS_INSTANCE_OFFSET_AUTO if TLAS is created with BindingMode SHADER_BINDING_MODE_PER_GEOMETRY, - /// or SHADER_BINDING_MODE_PER_INSTANCE otherwise. + /// Must be TLAS_INSTANCE_OFFSET_AUTO if BuildTLASAttribs::BindingMode that is not a SHADER_BINDING_USER_DEFINED. /// Only the lower 24 bits are used. Uint32 ContributionToHitGroupIndex DEFAULT_INITIALIZER(TLAS_INSTANCE_OFFSET_AUTO); @@ -1010,15 +1030,38 @@ struct TLASBuildInstanceData typedef struct TLASBuildInstanceData TLASBuildInstanceData; -/// Instance size in GPU side. +/// Top-level AS instance size in bytes in GPU side. /// Used to calculate size of BuildTLASAttribs::pInstanceBuffer. static const Uint32 TLAS_INSTANCE_DATA_SIZE = 64; +/// Defines shader binding mode. +DILIGENT_TYPED_ENUM(SHADER_BINDING_MODE, Uint8) +{ + /// Each geometry in each instance can have a unique hit shader. + /// See IShaderBindingTable::BindHitGroup(). + SHADER_BINDING_MODE_PER_GEOMETRY = 0, + + /// Each instance can have a unique hit shader. In this mode SBT buffer will use less memory. + /// See IShaderBindingTable::BindHitGroups(). + SHADER_BINDING_MODE_PER_INSTANCE, + + /// Single hit shader for top-level acceleration structure. + /// See IShaderBindingTable::BindHitGroupForAll(). + SHADER_BINDING_MODE_PER_ACCEL_STRUCT, + + /// The user must specify TLASBuildInstanceData::ContributionToHitGroupIndex and only use IShaderBindingTable::BindAll(). + SHADER_BINDING_USER_DEFINED, + + SHADER_BINDING_MODE_LAST = SHADER_BINDING_USER_DEFINED, +}; + + /// This structure is used by IDeviceContext::BuildTLAS(). struct BuildTLASAttribs { /// Target top-level AS. + /// Access to the TLAS must be externally synchronized. ITopLevelAS* pTLAS DEFAULT_INITIALIZER(nullptr); /// Top-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE). @@ -1028,10 +1071,14 @@ struct BuildTLASAttribs RESOURCE_STATE_TRANSITION_MODE BLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); /// A pointer to an array of InstanceCount TLASBuildInstanceData structures that contain instance data. + /// If Update is true: + /// - Any instance data can be changed. + /// - To disable instance set pBLAS to null. TLASBuildInstanceData const* pInstances DEFAULT_INITIALIZER(nullptr); /// The number of instances. /// Must be less than or equal to TopLevelASDesc::MaxInstanceCount. + /// If Update is true then count must be the same as used to build TLAS. Uint32 InstanceCount DEFAULT_INITIALIZER(0); /// The buffer that will be used to store instance data during AS building. @@ -1044,13 +1091,28 @@ struct BuildTLASAttribs /// Instance buffer state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE). RESOURCE_STATE_TRANSITION_MODE InstanceBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); - - /// AZ TODO + + /// The number of hit shaders that can be binded for single geometry or instance (depend on BindingMode). + /// Used to calculate TLASBuildInstanceData::ContributionToHitGroupIndex. + /// Ignored if BindingMode is SHADER_BINDING_USER_DEFINED. + /// You should use the same value in shader: + /// 'MultiplierForGeometryContributionToHitGroupIndex' argument in TraceRay() in HLSL, 'sbtRecordStride' argument in traceRay() in GLSL. Uint32 HitShadersPerInstance DEFAULT_INITIALIZER(1); + /// Base offset for hit group location. + /// Can be used to bind hit shaders for multiple acceleration structures, see IShaderBindingTable::BindHitGroup(). + /// Used to calculate TLASBuildInstanceData::ContributionToHitGroupIndex. + /// Ignored if BindingMode is SHADER_BINDING_USER_DEFINED. + Uint32 BaseContributionToHitGroupIndex DEFAULT_INITIALIZER(0); + + /// Hit shader binding mode, see Diligent::SHADER_BINDING_MODE. + /// Used to calculate TLASBuildInstanceData::ContributionToHitGroupIndex. + SHADER_BINDING_MODE BindingMode DEFAULT_INITIALIZER(SHADER_BINDING_MODE_PER_GEOMETRY); + /// Buffer that is used for acceleration structure building. /// Must be created with BIND_RAY_TRACING. /// Call ITopLevelAS::GetScratchBufferSizes().Build to get the minimal size for the scratch buffer. + /// Access to the TLAS must be externally synchronized. IBuffer* pScratchBuffer DEFAULT_INITIALIZER(nullptr); /// Offset from the beginning of the buffer. @@ -1059,6 +1121,12 @@ struct BuildTLASAttribs /// Scratch buffer state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE). RESOURCE_STATE_TRANSITION_MODE ScratchBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); + /// if false then TLAS will be built from scratch. + /// If true then previous content of TLAS will be updated. + /// pTLAS must be created with RAYTRACING_BUILD_AS_ALLOW_UPDATE flag. + /// An update will be faster than building an acceleration structure from scratch. + Bool Update DEFAULT_INITIALIZER(False); + #if DILIGENT_CPP_INTERFACE BuildTLASAttribs() noexcept {} #endif @@ -1070,11 +1138,13 @@ typedef struct BuildTLASAttribs BuildTLASAttribs; struct CopyBLASAttribs { /// Source bottom-level AS. + /// Access to the BLAS must be externally synchronized. IBottomLevelAS* pSrc DEFAULT_INITIALIZER(nullptr); /// Destination bottom-level AS. /// If Mode is COPY_AS_MODE_COMPACT then pDst must be created with CompactedSize /// that is greater or equal to the size returned by IDeviceContext::WriteBLASCompactedSize. + /// Access to the BLAS must be externally synchronized. IBottomLevelAS* pDst DEFAULT_INITIALIZER(nullptr); /// Acceleration structure copy mode, see Diligent::COPY_AS_MODE. @@ -1097,11 +1167,13 @@ typedef struct CopyBLASAttribs CopyBLASAttribs; struct CopyTLASAttribs { /// Source top-level AS. + /// Access to the TLAS must be externally synchronized. ITopLevelAS* pSrc DEFAULT_INITIALIZER(nullptr); /// Destination top-level AS. /// If Mode is COPY_AS_MODE_COMPACT then pDst must be created with CompactedSize /// that is greater or equal to size that returned by IDeviceContext::WriteTLASCompactedSize. + /// Access to the TLAS must be externally synchronized. ITopLevelAS* pDst DEFAULT_INITIALIZER(nullptr); /// Acceleration structure copy mode, see Diligent::COPY_AS_MODE. diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index 7e592ba7..56e72643 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -472,12 +472,15 @@ struct RayTracingPipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo /// Direct3D12 only: the name of the constant buffer that will be used by the local root signature. /// Ignored if RayTracingPipelineDesc::ShaderRecordSize is zero. + /// In Vulkan backend in HLSL add [[vk::shader_record_nv]] attribute to the constant buffer, in GLSL add shaderRecord layout to buffer. const char* pShaderRecordName DEFAULT_INITIALIZER(nullptr); /// Direct3D12 only: the maximum hit shader attribute size in bytes. + /// If zero then maximum allowed size will be used. Uint32 MaxAttributeSize DEFAULT_INITIALIZER(0); /// Direct3D12 only: the maximum payload size in bytes. + /// If zero then maximum allowed size will be used. Uint32 MaxPayloadSize DEFAULT_INITIALIZER(0); }; typedef struct RayTracingPipelineStateCreateInfo RayTracingPipelineStateCreateInfo; @@ -595,12 +598,9 @@ DILIGENT_BEGIN_INTERFACE(IPipelineState, IDeviceObject) /// This method must only be called for a ray tracing pipeline. /// \param [in] Name - Shader group name. + /// \return Shader group index or INVALID_INDEX if group does not exist. VIRTUAL Uint32 METHOD(GetShaderGroupIndex)(THIS_ const char* Name) CONST PURE; - - - /// AZ TODO: remove ? - VIRTUAL Uint32 METHOD(GetShaderGroupCount)(THIS) CONST PURE; }; DILIGENT_END_INTERFACE @@ -621,7 +621,6 @@ DILIGENT_END_INTERFACE # define IPipelineState_CreateShaderResourceBinding(This, ...) CALL_IFACE_METHOD(PipelineState, CreateShaderResourceBinding, This, __VA_ARGS__) # define IPipelineState_IsCompatibleWith(This, ...) CALL_IFACE_METHOD(PipelineState, IsCompatibleWith, This, __VA_ARGS__) # define IPipelineState_GetShaderGroupIndex(This, ...) CALL_IFACE_METHOD(PipelineState, GetShaderGroupIndex, This, __VA_ARGS__) -# define IPipelineState_GetShaderGroupCount(This) CALL_IFACE_METHOD(PipelineState, GetShaderGroupCount, This) // clang-format on diff --git a/Graphics/GraphicsEngine/interface/ShaderBindingTable.h b/Graphics/GraphicsEngine/interface/ShaderBindingTable.h index da650349..56455989 100644 --- a/Graphics/GraphicsEngine/interface/ShaderBindingTable.h +++ b/Graphics/GraphicsEngine/interface/ShaderBindingTable.h @@ -52,15 +52,32 @@ struct ShaderBindingTableDesc DILIGENT_DERIVE(DeviceObjectAttribs) /// Ray tracing pipeline state object from which shaders will be taken. IPipelineState* pPSO DEFAULT_INITIALIZER(nullptr); - /// AZ TODO - Uint32 HitShadersPerInstance DEFAULT_INITIALIZER(1); - #if DILIGENT_CPP_INTERFACE ShaderBindingTableDesc() noexcept {} #endif }; typedef struct ShaderBindingTableDesc ShaderBindingTableDesc; + +/// Defines shader binding table validation flags, see IShaderBindingTable::Verify(). +DILIGENT_TYPED_ENUM(SHADER_BINDING_VALIDATION_FLAGS, Uint8) +{ + /// Checks that all shaders are binded or inactive. + SHADER_BINDING_VALIDATION_SHADER_ONLY = 0x1, + + /// AZ TODO + SHADER_BINDING_VALIDATION_SHADER_RECORD = 0x2, + + /// AZ TODO + SHADER_BINDING_VALIDATION_TLAS = 0x4, + + SHADER_BINDING_VALIDATION_ALL = SHADER_BINDING_VALIDATION_SHADER_ONLY | + SHADER_BINDING_VALIDATION_SHADER_RECORD | + SHADER_BINDING_VALIDATION_TLAS +}; +DEFINE_FLAG_ENUM_OPERATORS(SHADER_BINDING_VALIDATION_FLAGS) + + /// AZ TODO struct BindAllAttribs { @@ -110,56 +127,147 @@ DILIGENT_BEGIN_INTERFACE(IShaderBindingTable, IDeviceObject) virtual const ShaderBindingTableDesc& DILIGENT_CALL_TYPE GetDesc() const override = 0; #endif - /// AZ TODO - VIRTUAL Bool METHOD(Verify)(THIS) CONST PURE; + /// Check that all shaders are binded, instances and geometries are not changed, shader record data are initialized. - /// AZ TODO + /// \param [in] Flags - Flags that used for validation. + /// \return True if SBT content are valid. + /// + /// \note Access to the SBT must be externally synchronized. + VIRTUAL Bool METHOD(Verify)(THIS_ + SHADER_BINDING_VALIDATION_FLAGS Flags) CONST PURE; + + + /// Reset SBT with new pipeline state. This is more effectively than creating new SBT. + + /// \note Access to the SBT must be externally synchronized. VIRTUAL void METHOD(Reset)(THIS_ - const ShaderBindingTableDesc REF Desc) PURE; + IPipelineState* pPSO) PURE; - /// AZ TODO - VIRTUAL void METHOD(ResetHitGroups)(THIS_ - Uint32 HitShadersPerInstance) PURE; + + /// When TLAS or BLAS was rebuilded or updated, hit group shader bindings may become invalid, + /// you can reset only hit groups and keep ray-gen, miss and callable shader bindings. - /// AZ TODO + /// \note Access to the SBT must be externally synchronized. + VIRTUAL void METHOD(ResetHitGroups)(THIS) PURE; + + + /// Bind ray-generation shader. + + /// \param [in] pShaderGroupName - ray-generation shader name that specified in RayTracingGeneralShaderGroup::Name. + /// \param [in] pData - shader record data, can be null. + /// \param [in] DataSize - shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize. + /// + /// \note Access to the SBT must be externally synchronized. VIRTUAL void METHOD(BindRayGenShader)(THIS_ - const char* ShaderGroupName, - const void* Data DEFAULT_INITIALIZER(nullptr), + const char* pShaderGroupName, + const void* pData DEFAULT_INITIALIZER(nullptr), Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE; - /// AZ TODO + + /// Bind ray-miss shader. + + /// \param [in] pShaderGroupName - ray-miss shader name that specified in RayTracingGeneralShaderGroup::Name, + /// can be null to make shader inactive. + /// \param [in] MissIndex - miss shader offset in shader binding table, use the same value as in shader: + /// 'MissShaderIndex' argument in TraceRay() in HLSL, 'missIndex' in traceRay() in GLSL. + /// \param [in] pData - shader record data, can be null. + /// \param [in] DataSize - shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize. + /// + /// \note Access to the SBT must be externally synchronized. VIRTUAL void METHOD(BindMissShader)(THIS_ - const char* ShaderGroupName, + const char* pShaderGroupName, Uint32 MissIndex, - const void* Data DEFAULT_INITIALIZER(nullptr), + const void* pData DEFAULT_INITIALIZER(nullptr), Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE; - /// AZ TODO + + /// Bind hit group for specified geometry in instance. + + /// \param [in] pTLAS - top-level AS, used to calculate offset for instance. + /// \param [in] pInstanceName - instance name, see TLASBuildInstanceData::InstanceName. + /// \param [in] pGeometryName - geometry name, see BLASBuildTriangleData::GeometryName and BLASBuildBoundingBoxData::GeometryName. + /// \param [in] RayOffsetInHitGroupIndex - ray offset in shader binding table, use the same value as in shader: + /// 'RayContributionToHitGroupIndex' argument in TraceRay() in HLSL, 'sbtRecordOffset' argument in traceRay() in GLSL. + /// Must be less than HitShadersPerInstance. + /// \param [in] pShaderGroupName - hit group name that specified in RayTracingTriangleHitShaderGroup::Name and RayTracingProceduralHitShaderGroup::Name, + /// can be null to make shader inactive. + /// \param [in] pData - shader record data, can be null. + /// \param [in] DataSize - shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize. + /// + /// \note Access to the SBT must be externally synchronized. + /// Access to the TLAS must be externally synchronized. + /// Access to the BLAS that was used in TLAS instance with name pInstanceName must be externally synchronized. VIRTUAL void METHOD(BindHitGroup)(THIS_ ITopLevelAS* pTLAS, - const char* InstanceName, - const char* GeometryName, + const char* pInstanceName, + const char* pGeometryName, Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data DEFAULT_INITIALIZER(nullptr), + const char* pShaderGroupName, + const void* pData DEFAULT_INITIALIZER(nullptr), Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE; - /// AZ TODO + + /// Bind hit group for each geometries in specified instance. + + /// \param [in] pTLAS - top-level AS, used to calculate offset for instance. + /// \param [in] pInstanceName - instance name, see TLASBuildInstanceData::InstanceName. + /// \param [in] RayOffsetInHitGroupIndex - ray offset in shader binding table, use the same value as in shader: + /// 'RayContributionToHitGroupIndex' argument in TraceRay() in HLSL, 'sbtRecordOffset' argument in traceRay() in GLSL. + /// Must be less than HitShadersPerInstance. + /// \param [in] pShaderGroupName - hit group name that specified in RayTracingTriangleHitShaderGroup::Name and RayTracingProceduralHitShaderGroup::Name, + /// can be null to make shader inactive. + /// \param [in] pData - shader record data, can be null. + /// \param [in] DataSize - shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize. + /// + /// \note Access to the SBT must be externally synchronized. + /// Access to the TLAS must be externally synchronized. VIRTUAL void METHOD(BindHitGroups)(THIS_ ITopLevelAS* pTLAS, - const char* InstanceName, + const char* pInstanceName, Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data DEFAULT_INITIALIZER(nullptr), + const char* pShaderGroupName, + const void* pData DEFAULT_INITIALIZER(nullptr), Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE; - /// AZ TODO + + /// Bind hit group for each instances in top-level AS. + + /// \param [in] pTLAS - top-level AS, used to calculate offset for instance. + /// \param [in] RayOffsetInHitGroupIndex - ray offset in shader binding table, use the same value as in shader: + /// 'RayContributionToHitGroupIndex' argument in TraceRay() in HLSL, 'sbtRecordOffset' argument in traceRay() in GLSL. + /// Must be less than HitShadersPerInstance. + /// \param [in] pShaderGroupName - hit group name that specified in RayTracingTriangleHitShaderGroup::Name and RayTracingProceduralHitShaderGroup::Name, + /// can be null to make shader inactive. + /// \param [in] pData - shader record data, can be null. + /// \param [in] DataSize - shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize. + /// + /// \note Access to the SBT must be externally synchronized. + /// Access to the TLAS must be externally synchronized. + VIRTUAL void METHOD(BindHitGroupForAll)(THIS_ + ITopLevelAS* pTLAS, + Uint32 RayOffsetInHitGroupIndex, + const char* pShaderGroupName, + const void* pData DEFAULT_INITIALIZER(nullptr), + Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE; + + + /// Bind callable shader. + + /// \param [in] pShaderGroupName - callable shader name that specified in RayTracingGeneralShaderGroup::Name, + /// can be null to make shader inactive. + /// \param [in] CallableIndex - callable shader offset in shader binding table, use the same value as in shader: + /// 'ShaderIndex' argument in CallShader() in HLSL, 'callable' argument in executeCallable() in GLSL. + /// \param [in] pData - shader record data, can be null. + /// \param [in] DataSize - shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize. + /// + /// \note Access to the SBT must be externally synchronized. VIRTUAL void METHOD(BindCallableShader)(THIS_ - const char* ShaderGroupName, + const char* pShaderGroupName, Uint32 CallableIndex, - const void* Data DEFAULT_INITIALIZER(nullptr), + const void* pData DEFAULT_INITIALIZER(nullptr), Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE; + /// AZ TODO VIRTUAL void METHOD(BindAll)(THIS_ const BindAllAttribs REF Attribs) PURE; @@ -172,13 +280,14 @@ DILIGENT_END_INTERFACE // clang-format off -# define IShaderBindingTable_Verify(This) CALL_IFACE_METHOD(ShaderBindingTable, Verify, This) +# define IShaderBindingTable_Verify(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, Verify, This, __VA_ARGS__) # define IShaderBindingTable_Reset(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, Reset, This, __VA_ARGS__) -# define IShaderBindingTable_ResetHitGroups(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, ResetHitGroups, This, __VA_ARGS__) +# define IShaderBindingTable_ResetHitGroups(This) CALL_IFACE_METHOD(ShaderBindingTable, ResetHitGroups, This) # define IShaderBindingTable_BindRayGenShader(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindRayGenShader, This, __VA_ARGS__) # define IShaderBindingTable_BindMissShader(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindMissShader, This, __VA_ARGS__) # define IShaderBindingTable_BindHitGroup(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindHitGroup, This, __VA_ARGS__) # define IShaderBindingTable_BindHitGroups(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindHitGroups, This, __VA_ARGS__) +# define IShaderBindingTable_BindHitGroupForAll(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindHitGroupForAll, This, __VA_ARGS__) # define IShaderBindingTable_BindCallableShader(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindCallableShader, This, __VA_ARGS__) # define IShaderBindingTable_BindAll(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindAll, This, __VA_ARGS__) diff --git a/Graphics/GraphicsEngine/interface/TopLevelAS.h b/Graphics/GraphicsEngine/interface/TopLevelAS.h index 0c02b920..6eaee93b 100644 --- a/Graphics/GraphicsEngine/interface/TopLevelAS.h +++ b/Graphics/GraphicsEngine/interface/TopLevelAS.h @@ -45,20 +45,6 @@ static const INTERFACE_ID IID_TopLevelAS = // clang-format off -/// Defines shader binding mode. -DILIGENT_TYPED_ENUM(SHADER_BINDING_MODE, Uint8) -{ - /// Each geometry in each instance can have a unique shader. - SHADER_BINDING_MODE_PER_GEOMETRY = 0, - - /// Each instance can have a unique shader. In this mode SBT buffer will use less memory. - SHADER_BINDING_MODE_PER_INSTANCE, - - /// The user must specify TLASBuildInstanceData::InstanceContributionToHitGroupIndex and only use IShaderBindingTable::BindAll(). - SHADER_BINDING_USER_DEFINED, -}; - - /// Top-level AS description. struct TopLevelASDesc DILIGENT_DERIVE(DeviceObjectAttribs) @@ -69,12 +55,8 @@ struct TopLevelASDesc DILIGENT_DERIVE(DeviceObjectAttribs) RAYTRACING_BUILD_AS_FLAGS Flags DEFAULT_INITIALIZER(RAYTRACING_BUILD_AS_NONE); /// The size returned by IDeviceContext::WriteTLASCompactedSize(), if this acceleration structure - /// is going to be the target of a compacting copy (IDeviceContext::CopyTLAS() with COPY_AS_MODE_COMPACT). + /// is going to be the target of a compacting copy command (IDeviceContext::CopyTLAS() with COPY_AS_MODE_COMPACT). Uint32 CompactedSize DEFAULT_INITIALIZER(0); - - /// Binding mode that i used for TLASBuildInstanceData::ContributionToHitGroupIndex calculation, - /// see Diligent::SHADER_BINDING_MODE. - SHADER_BINDING_MODE BindingMode DEFAULT_INITIALIZER(SHADER_BINDING_MODE_PER_GEOMETRY); /// Defines which command queues this BLAS can be used with. Uint64 CommandQueueMask DEFAULT_INITIALIZER(1); @@ -91,6 +73,10 @@ struct TLASInstanceDesc { /// Index that corresponds to the one specified in TLASBuildInstanceData::ContributionToHitGroupIndex. Uint32 ContributionToHitGroupIndex DEFAULT_INITIALIZER(0); + + /// The autogenerated index of the instance. + /// Same as InstanceIndex() in HLSL and gl_InstanceID in GLSL. + Uint32 InstanceIndex DEFAULT_INITIALIZER(0); /// Bottom-level AS that is specified in TLASBuildInstanceData::pBLAS. IBottomLevelAS* pBLAS DEFAULT_INITIALIZER(nullptr); @@ -122,21 +108,40 @@ DILIGENT_BEGIN_INTERFACE(ITopLevelAS, IDeviceObject) /// Returns instance description that can be used in shader binding table. /// \param [in] Name - Instance name that is specified in TLASBuildInstanceData::InstanceName. - /// \return structure object. + /// \return TLASInstanceDesc object, see Diligent::TLASInstanceDesc. + /// If instance does not exist then TLASInstanceDesc::ContributionToHitGroupIndex + /// and TLASInstanceDesc::InstanceIndex set to INVALID_INDEX. + /// + /// \note Access to the TLAS must be externally synchronized. VIRTUAL TLASInstanceDesc METHOD(GetInstanceDesc)(THIS_ const char* Name) CONST PURE; + + /// Returns the first and last hit group location that is calculated during build or update operation, + /// see IDeviceContext::BuildTLAS(). + + /// \param [out] FirstContributionToHitGroupIndex - Returns the BuildTLASAttribs::BaseContributionToHitGroupIndex value + /// as used in last build or copy operation. + /// \param [out] LastContributionToHitGroupIndex - Returns the maximum value that used in hit group shader location calculation. + /// + /// \note Access to the TLAS must be externally synchronized. + VIRTUAL void METHOD(GetContributionToHitGroupIndex)(THIS_ + Uint32 REF FirstContributionToHitGroupIndex, + Uint32 REF LastContributionToHitGroupIndex) CONST PURE; + + /// Returns scratch buffer info for the current acceleration structure. - /// \return structure object. + /// \return ScratchBufferSizes object, see Diligent::ScratchBufferSizes. VIRTUAL ScratchBufferSizes METHOD(GetScratchBufferSizes)(THIS) CONST PURE; /// Returns native acceleration structure handle specific to the underlying graphics API /// \return pointer to ID3D12Resource interface, for D3D12 implementation\n - /// VkAccelerationStructureKHR handle, for Vulkan implementation + /// VkAccelerationStructure handle, for Vulkan implementation VIRTUAL void* METHOD(GetNativeHandle)(THIS) PURE; + /// Sets the acceleration structure usage state. /// \note This method does not perform state transition, but @@ -147,6 +152,7 @@ DILIGENT_BEGIN_INTERFACE(ITopLevelAS, IDeviceObject) VIRTUAL void METHOD(SetState)(THIS_ RESOURCE_STATE State) PURE; + /// Returns the internal acceleration structure state VIRTUAL RESOURCE_STATE METHOD(GetState)(THIS) CONST PURE; }; @@ -158,11 +164,12 @@ DILIGENT_END_INTERFACE // clang-format off -# define ITopLevelAS_GetInstanceDesc(This, ...) CALL_IFACE_METHOD(TopLevelAS, GetInstanceDesc, This, __VA_ARGS__) -# define ITopLevelAS_GetScratchBufferSizes(This) CALL_IFACE_METHOD(TopLevelAS, GetScratchBufferSizes, This) -# define ITopLevelAS_GetNativeHandle(This) CALL_IFACE_METHOD(TopLevelAS, GetNativeHandle, This) -# define ITopLevelAS_SetState(This, ...) CALL_IFACE_METHOD(TopLevelAS, SetState, This, __VA_ARGS__) -# define ITopLevelAS_GetState(This) CALL_IFACE_METHOD(TopLevelAS, GetState, This) +# define ITopLevelAS_GetInstanceDesc(This, ...) CALL_IFACE_METHOD(TopLevelAS, GetInstanceDesc, This, __VA_ARGS__) +# define ITopLevelAS_GetContributionToHitGroupIndex(This, ...) CALL_IFACE_METHOD(TopLevelAS, GetContributionToHitGroupIndex, This, __VA_ARGS__) +# define ITopLevelAS_GetScratchBufferSizes(This) CALL_IFACE_METHOD(TopLevelAS, GetScratchBufferSizes, This) +# define ITopLevelAS_GetNativeHandle(This) CALL_IFACE_METHOD(TopLevelAS, GetNativeHandle, This) +# define ITopLevelAS_SetState(This, ...) CALL_IFACE_METHOD(TopLevelAS, SetState, This, __VA_ARGS__) +# define ITopLevelAS_GetState(This) CALL_IFACE_METHOD(TopLevelAS, GetState, This) // clang-format on diff --git a/Graphics/GraphicsEngine/src/BottomLevelASBase.cpp b/Graphics/GraphicsEngine/src/BottomLevelASBase.cpp index 1059f451..81168f61 100644 --- a/Graphics/GraphicsEngine/src/BottomLevelASBase.cpp +++ b/Graphics/GraphicsEngine/src/BottomLevelASBase.cpp @@ -103,16 +103,12 @@ void ValidateBottomLevelASDesc(const BottomLevelASDesc& Desc) noexcept(false) #undef LOG_BLAS_ERROR_AND_THROW } -void CopyBottomLevelASDesc(const BottomLevelASDesc& SrcDesc, - BottomLevelASDesc& DstDesc, - LinearAllocator& MemPool, - std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>& NameToIndex) noexcept(false) +void CopyBLASGeometryDesc(const BottomLevelASDesc& SrcDesc, + BottomLevelASDesc& DstDesc, + LinearAllocator& MemPool, + const BLASNameToIndex* pSrcNameToIndex, + BLASNameToIndex& DstNameToIndex) noexcept(false) { - // Preserve original name - const auto* Name = DstDesc.Name; - DstDesc = SrcDesc; - DstDesc.Name = Name; - if (SrcDesc.pTriangles != nullptr) { MemPool.AddSpace<decltype(*SrcDesc.pTriangles)>(SrcDesc.TriangleCount); @@ -129,13 +125,24 @@ void CopyBottomLevelASDesc(const BottomLevelASDesc& { const auto* SrcGeoName = SrcDesc.pTriangles[i].GeometryName; pTriangles[i].GeometryName = MemPool.CopyString(SrcGeoName); - bool IsUniqueName = NameToIndex.emplace(SrcGeoName, i).second; + Uint32 ActualIndex = INVALID_INDEX; + + if (pSrcNameToIndex) + { + auto iter = pSrcNameToIndex->find(SrcGeoName); + VERIFY_EXPR(iter != pSrcNameToIndex->end()); + ActualIndex = iter->second.ActualIndex; + } + + bool IsUniqueName = DstNameToIndex.emplace(SrcGeoName, BLASGeomIndex{i, ActualIndex}).second; if (!IsUniqueName) LOG_ERROR_AND_THROW("Geometry name '", SrcGeoName, "' is not unique"); } - DstDesc.pTriangles = pTriangles; - DstDesc.pBoxes = nullptr; - DstDesc.BoxCount = 0; + + DstDesc.pTriangles = pTriangles; + DstDesc.TriangleCount = SrcDesc.TriangleCount; + DstDesc.pBoxes = nullptr; + DstDesc.BoxCount = 0; } else if (SrcDesc.pBoxes != nullptr) { @@ -153,11 +160,22 @@ void CopyBottomLevelASDesc(const BottomLevelASDesc& { const auto* SrcGeoName = SrcDesc.pBoxes[i].GeometryName; pBoxes[i].GeometryName = MemPool.CopyString(SrcGeoName); - bool IsUniqueName = NameToIndex.emplace(SrcGeoName, i).second; + Uint32 ActualIndex = INVALID_INDEX; + + if (pSrcNameToIndex) + { + auto iter = pSrcNameToIndex->find(SrcGeoName); + VERIFY_EXPR(iter != pSrcNameToIndex->end()); + ActualIndex = iter->second.ActualIndex; + } + + bool IsUniqueName = DstNameToIndex.emplace(SrcGeoName, BLASGeomIndex{i, ActualIndex}).second; if (!IsUniqueName) LOG_ERROR_AND_THROW("Geometry name '", SrcGeoName, "' is not unique"); } + DstDesc.pBoxes = pBoxes; + DstDesc.BoxCount = SrcDesc.BoxCount; DstDesc.pTriangles = nullptr; DstDesc.TriangleCount = 0; } diff --git a/Graphics/GraphicsEngine/src/DeviceContextBase.cpp b/Graphics/GraphicsEngine/src/DeviceContextBase.cpp index a526bd37..beb02e00 100644 --- a/Graphics/GraphicsEngine/src/DeviceContextBase.cpp +++ b/Graphics/GraphicsEngine/src/DeviceContextBase.cpp @@ -349,14 +349,26 @@ bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs) CHECK_BUILD_BLAS_ATTRIBS(Attribs.BoxDataCount <= BLASDesc.BoxCount, "BoxDataCount must be less than or equal to pBLAS->GetDesc().BoxCount"); CHECK_BUILD_BLAS_ATTRIBS(Attribs.TriangleDataCount <= BLASDesc.TriangleCount, "TriangleDataCount must be less than or equal to pBLAS->GetDesc().TriangleCount"); + if (Attribs.Update) + { + CHECK_BUILD_BLAS_ATTRIBS((BLASDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_UPDATE) == RAYTRACING_BUILD_AS_ALLOW_UPDATE, + "Update is true, but BLAS created without RAYTRACING_BUILD_AS_ALLOW_UPDATE flag"); + + const Uint32 GeomCount = Attribs.pBLAS->GetActualGeometryCount(); + CHECK_BUILD_BLAS_ATTRIBS(Attribs.BoxDataCount == 0 || Attribs.BoxDataCount == GeomCount, + "Update is true, but BoxDataCount does not match with a previous value (", GeomCount, ")"); + CHECK_BUILD_BLAS_ATTRIBS(Attribs.TriangleDataCount == 0 || Attribs.TriangleDataCount == GeomCount, + "Update is true, but TriangleDataCount does not match with a previous value (", GeomCount, ")"); + } + for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i) { const auto& tri = Attribs.pTriangleData[i]; const Uint32 VertexSize = GetValueSize(tri.VertexValueType) * tri.VertexComponentCount; const Uint32 VertexDataSize = tri.VertexStride * tri.VertexCount; - const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryIndex(tri.GeometryName); + const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryDescIndex(tri.GeometryName); - CHECK_BUILD_BLAS_ATTRIBS(GeomIndex != InvalidGeometryIndex, + CHECK_BUILD_BLAS_ATTRIBS(GeomIndex != INVALID_INDEX, "pTriangleData[", i, "].GeometryName (", tri.GeometryName, ") is not found in BLAS description"); const auto& TriDesc = BLASDesc.pTriangles[GeomIndex]; @@ -376,10 +388,11 @@ bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs) CHECK_BUILD_BLAS_ATTRIBS(tri.pVertexBuffer != nullptr, "pTriangleData[", i, "].pVertexBuffer must not be null"); - CHECK_BUILD_BLAS_ATTRIBS((tri.pVertexBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, + const BufferDesc& VertBufDesc = tri.pVertexBuffer->GetDesc(); + CHECK_BUILD_BLAS_ATTRIBS((VertBufDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, "pTriangleData[", i, "].pVertexBuffer was not created with BIND_RAY_TRACING flag"); - CHECK_BUILD_BLAS_ATTRIBS(tri.VertexOffset + VertexDataSize <= tri.pVertexBuffer->GetDesc().uiSizeInBytes, + CHECK_BUILD_BLAS_ATTRIBS(tri.VertexOffset + VertexDataSize <= VertBufDesc.uiSizeInBytes, "pTriangleData[", i, "].pVertexBuffer is too small for the specified VertexStride (", tri.VertexStride, ") and VertexCount (", tri.VertexCount, "): at least ", tri.VertexOffset + VertexDataSize, " bytes are required"); @@ -395,11 +408,13 @@ bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs) { CHECK_BUILD_BLAS_ATTRIBS(tri.pIndexBuffer != nullptr, "pTriangleData[", i, "].pIndexBuffer must not be null"); - CHECK_BUILD_BLAS_ATTRIBS((tri.pIndexBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, + const BufferDesc& InstBufDesc = tri.pIndexBuffer->GetDesc(); + const Uint32 IndexDataSize = tri.PrimitiveCount * 3 * GetValueSize(tri.IndexType); + + CHECK_BUILD_BLAS_ATTRIBS((InstBufDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, "pTriangleData[", i, "].pIndexBuffer was not created with BIND_RAY_TRACING flag"); - const Uint32 IndexDataSize = tri.PrimitiveCount * 3 * GetValueSize(tri.IndexType); - CHECK_BUILD_BLAS_ATTRIBS(tri.IndexOffset + IndexDataSize <= tri.pIndexBuffer->GetDesc().uiSizeInBytes, + CHECK_BUILD_BLAS_ATTRIBS(tri.IndexOffset + IndexDataSize <= InstBufDesc.uiSizeInBytes, "pTriangleData[", i, "].pIndexBuffer is too small for specified IndexType and IndexCount: at least", tri.IndexOffset + IndexDataSize, " bytes are required"); } @@ -425,9 +440,9 @@ bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs) { const auto& box = Attribs.pBoxData[i]; const Uint32 BoxSize = sizeof(float) * 6; - const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryIndex(box.GeometryName); + const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryDescIndex(box.GeometryName); - CHECK_BUILD_BLAS_ATTRIBS(GeomIndex != InvalidGeometryIndex, + CHECK_BUILD_BLAS_ATTRIBS(GeomIndex != INVALID_INDEX, "pBoxData[", i, "].GeometryName (", box.GeometryName, ") is not found in BLAS description"); const auto& BoxDesc = BLASDesc.pBoxes[GeomIndex]; @@ -449,8 +464,12 @@ bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs) CHECK_BUILD_BLAS_ATTRIBS(Attribs.ScratchBufferOffset <= ScratchDesc.uiSizeInBytes, "ScratchBufferOffset (", Attribs.ScratchBufferOffset, ") is greater than the buffer size (", ScratchDesc.uiSizeInBytes, ")"); - CHECK_BUILD_BLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pBLAS->GetScratchBufferSizes().Build, - "pScratchBuffer size is too small, use pBLAS->GetScratchBufferSizes().Build to get the required size for the scratch buffer"); + if (Attribs.Update) + CHECK_BUILD_BLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pBLAS->GetScratchBufferSizes().Update, + "pScratchBuffer size is too small, use pBLAS->GetScratchBufferSizes().Update to get the required size for the scratch buffer"); + else + CHECK_BUILD_BLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pBLAS->GetScratchBufferSizes().Build, + "pScratchBuffer size is too small, use pBLAS->GetScratchBufferSizes().Build to get the required size for the scratch buffer"); CHECK_BUILD_BLAS_ATTRIBS((ScratchDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, "pScratchBuffer was not created with BIND_RAY_TRACING flag"); @@ -461,7 +480,7 @@ bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs) } -bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs) +bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs, Uint32 PrevInstanceCount) { #define CHECK_BUILD_TLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Build TLAS attribs are invalid: ", __VA_ARGS__) @@ -469,7 +488,9 @@ bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs) CHECK_BUILD_TLAS_ATTRIBS(Attribs.pScratchBuffer != nullptr, "pScratchBuffer must not be null"); CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstances != nullptr, "pInstances must not be null"); CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstanceBuffer != nullptr, "pInstanceBuffer must not be null"); - CHECK_BUILD_TLAS_ATTRIBS(Attribs.HitShadersPerInstance != 0, "HitShadersPerInstance must be greater than 0"); + + CHECK_BUILD_TLAS_ATTRIBS(Attribs.BindingMode == SHADER_BINDING_USER_DEFINED || Attribs.HitShadersPerInstance != 0, + "HitShadersPerInstance must be greater than 0 if BindingMode is not SHADER_BINDING_USER_DEFINED"); const auto& TLASDesc = Attribs.pTLAS->GetDesc(); @@ -477,30 +498,49 @@ bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs) "InstanceCount (", Attribs.InstanceCount, ") must be less than or equal to pTLAS->GetDesc().MaxInstanceCount (", TLASDesc.MaxInstanceCount, ")"); - const auto& InstDesc = Attribs.pInstanceBuffer->GetDesc(); - const auto InstDataSize = size_t{Attribs.InstanceCount} * size_t{TLAS_INSTANCE_DATA_SIZE}; + if (Attribs.Update) + { + CHECK_BUILD_TLAS_ATTRIBS((TLASDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_UPDATE) == RAYTRACING_BUILD_AS_ALLOW_UPDATE, + "Update is true, but TLAS created without RAYTRACING_BUILD_AS_ALLOW_UPDATE flag"); + CHECK_BUILD_TLAS_ATTRIBS(PrevInstanceCount == Attribs.InstanceCount, + "Update is true, but InstanceCount (", Attribs.InstanceCount, ") does not match with the previous value (", PrevInstanceCount, ")"); + } - Uint32 AutoOffsetCounter = 0; + const auto& InstDesc = Attribs.pInstanceBuffer->GetDesc(); + const auto InstDataSize = size_t{Attribs.InstanceCount} * size_t{TLAS_INSTANCE_DATA_SIZE}; + Uint32 AutoOffsetCounter = 0; // Calculate instance data size for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) { - VERIFY((Attribs.pInstances[i].CustomId & ~0x00FFFFFF) == 0, "Only the lower 24 bits are used"); + constexpr Uint32 BitMask = (1u << 24) - 1; + const auto& Inst = Attribs.pInstances[i]; + + VERIFY((Inst.CustomId & ~BitMask) == 0, "Only the lower 24 bits are used"); - VERIFY(Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO || - (Attribs.pInstances[i].ContributionToHitGroupIndex & ~0x00FFFFFF) == 0, + VERIFY(Inst.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO || + (Inst.ContributionToHitGroupIndex & ~BitMask) == 0, "Only the lower 24 bits are used"); - CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstances[i].InstanceName != nullptr, "pInstances[", i, "].InstanceName must not be null"); - CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstances[i].pBLAS != nullptr, "pInstances[", i, "].pBLAS must not be null"); + CHECK_BUILD_TLAS_ATTRIBS(Inst.InstanceName != nullptr, "pInstances[", i, "].InstanceName must not be null"); - if (Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) + if (Attribs.Update) + { + const TLASInstanceDesc IDesc = Attribs.pTLAS->GetInstanceDesc(Inst.InstanceName); + CHECK_BUILD_TLAS_ATTRIBS(IDesc.InstanceIndex != INVALID_INDEX, "Update is true, but pInstances[", i, "].InstanceName does not exists"); + } + else + { + CHECK_BUILD_TLAS_ATTRIBS(Inst.pBLAS != nullptr, "pInstances[", i, "].pBLAS must not be null"); + } + + if (Inst.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) ++AutoOffsetCounter; - CHECK_BUILD_TLAS_ATTRIBS(TLASDesc.BindingMode == SHADER_BINDING_USER_DEFINED || Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO, + CHECK_BUILD_TLAS_ATTRIBS(Attribs.BindingMode == SHADER_BINDING_USER_DEFINED || Inst.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO, "pInstances[", i, "].ContributionToHitGroupIndex must be TLAS_INSTANCE_OFFSET_AUTO " - "if TLAS is created with BindingMode that is not SHADER_BINDING_USER_DEFINED"); + "if BindingMode is not SHADER_BINDING_USER_DEFINED"); } CHECK_BUILD_TLAS_ATTRIBS(AutoOffsetCounter == 0 || AutoOffsetCounter == Attribs.InstanceCount, @@ -521,8 +561,12 @@ bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs) CHECK_BUILD_TLAS_ATTRIBS(Attribs.ScratchBufferOffset <= ScratchDesc.uiSizeInBytes, "ScratchBufferOffset (", Attribs.ScratchBufferOffset, ") is greater than the buffer size (", ScratchDesc.uiSizeInBytes, ")"); - CHECK_BUILD_TLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pTLAS->GetScratchBufferSizes().Build, - "pScratchBuffer size is too small, use pTLAS->GetScratchBufferSizes().Build to get the required size for scratch buffer"); + if (Attribs.Update) + CHECK_BUILD_TLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pTLAS->GetScratchBufferSizes().Update, + "pScratchBuffer size is too small, use pTLAS->GetScratchBufferSizes().Update to get the required size for scratch buffer"); + else + CHECK_BUILD_TLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pTLAS->GetScratchBufferSizes().Build, + "pScratchBuffer size is too small, use pTLAS->GetScratchBufferSizes().Build to get the required size for scratch buffer"); CHECK_BUILD_TLAS_ATTRIBS((ScratchDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, "pScratchBuffer was not created with BIND_RAY_TRACING flag"); @@ -532,7 +576,7 @@ bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs) } -bool VerifyCopyBLASAttribs(const CopyBLASAttribs& Attribs) +bool VerifyCopyBLASAttribs(const IRenderDevice* pDevice, const CopyBLASAttribs& Attribs) { #define CHECK_COPY_BLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Copy BLAS attribs are invalid: ", __VA_ARGS__) @@ -541,48 +585,63 @@ bool VerifyCopyBLASAttribs(const CopyBLASAttribs& Attribs) if (Attribs.Mode == COPY_AS_MODE_CLONE) { - auto& SrcDesc = Attribs.pSrc->GetDesc(); - auto& DstDesc = Attribs.pDst->GetDesc(); - - CHECK_COPY_BLAS_ATTRIBS(SrcDesc.TriangleCount == DstDesc.TriangleCount, - "Src BLAS triangle count (", SrcDesc.TriangleCount, ") must be equal to the dst BLAS triangle count (", DstDesc.TriangleCount, ")"); - - CHECK_COPY_BLAS_ATTRIBS(SrcDesc.BoxCount == DstDesc.BoxCount, - "Src BLAS box count (", SrcDesc.BoxCount, ") must be equal to the dst BLAS box count (", DstDesc.BoxCount, ")"); - - CHECK_COPY_BLAS_ATTRIBS(SrcDesc.Flags == DstDesc.Flags, - "Source and destination BLASes must have been created with the same flags"); - - for (Uint32 i = 0; i < SrcDesc.TriangleCount; ++i) - { - auto& SrcTri = SrcDesc.pTriangles[i]; - auto& DstTri = DstDesc.pTriangles[i]; - - CHECK_COPY_BLAS_ATTRIBS(SrcTri.MaxVertexCount == DstTri.MaxVertexCount, - "MaxVertexCount value (", SrcTri.MaxVertexCount, ") in source triangle description at index ", i, - " does not match MaxVertexCount value (", DstTri.MaxVertexCount, ") in the destination description"); - CHECK_COPY_BLAS_ATTRIBS(SrcTri.VertexValueType == DstTri.VertexValueType, - "VertexValueType value (", GetValueTypeString(SrcTri.VertexValueType), ") in source triangle description at index ", i, - " does not match VertexValueType value (", GetValueTypeString(DstTri.VertexValueType), ") in destination description"); - CHECK_COPY_BLAS_ATTRIBS(SrcTri.VertexComponentCount == DstTri.VertexComponentCount, - "VertexComponentCount value (", Uint32{SrcTri.VertexComponentCount}, ") in source triangle description at index ", i, - " does not match VertexComponentCount value (", Uint32{DstTri.VertexComponentCount}, ") in destination description"); - CHECK_COPY_BLAS_ATTRIBS(SrcTri.MaxPrimitiveCount == DstTri.MaxPrimitiveCount, - "MaxPrimitiveCount value (", SrcTri.MaxPrimitiveCount, ") in source triangle description at index ", i, - " does not match MaxPrimitiveCount value (", DstTri.MaxPrimitiveCount, ") in destination description"); - CHECK_COPY_BLAS_ATTRIBS(SrcTri.IndexType == DstTri.IndexType, - "IndexType value (", GetValueTypeString(SrcTri.IndexType), ") in source triangle description at index ", i, - " does not match IndexType value (", GetValueTypeString(DstTri.IndexType), ") in destination description"); - CHECK_COPY_BLAS_ATTRIBS(SrcTri.AllowsTransforms == DstTri.AllowsTransforms, - "AllowsTransforms value (", (SrcTri.AllowsTransforms ? "true" : "false"), ") in source triangle description at index ", i, - " does not match AllowsTransforms value (", (DstTri.AllowsTransforms ? "true" : "false"), ") in destination description"); - } - - for (Uint32 i = 0; i < SrcDesc.BoxCount; ++i) + if (pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_VULKAN) { - CHECK_COPY_BLAS_ATTRIBS(SrcDesc.pBoxes[i].MaxBoxCount == DstDesc.pBoxes[i].MaxBoxCount, - "MaxBoxCountt value (", SrcDesc.pBoxes[i].MaxBoxCount, ") in source box description at index ", i, - " does not match MaxBoxCount value (", DstDesc.pBoxes[i].MaxBoxCount, ") in destination description"); + auto& SrcDesc = Attribs.pSrc->GetDesc(); + auto& DstDesc = Attribs.pDst->GetDesc(); + + CHECK_COPY_BLAS_ATTRIBS(SrcDesc.TriangleCount == DstDesc.TriangleCount, + "Src BLAS triangle count (", SrcDesc.TriangleCount, ") must be equal to the dst BLAS triangle count (", DstDesc.TriangleCount, ")"); + + CHECK_COPY_BLAS_ATTRIBS(SrcDesc.BoxCount == DstDesc.BoxCount, + "Src BLAS box count (", SrcDesc.BoxCount, ") must be equal to the dst BLAS box count (", DstDesc.BoxCount, ")"); + + CHECK_COPY_BLAS_ATTRIBS(SrcDesc.Flags == DstDesc.Flags, + "Source and destination BLASes must have been created with the same flags"); + + for (Uint32 i = 0; i < SrcDesc.TriangleCount; ++i) + { + const BLASTriangleDesc& SrcTri = SrcDesc.pTriangles[i]; + const Uint32 Index = Attribs.pDst->GetGeometryDescIndex(SrcTri.GeometryName); + CHECK_COPY_BLAS_ATTRIBS(Index != INVALID_INDEX, + "Src GeometryName ('", SrcTri.GeometryName, "') at index ", i, " is not found in pDst"); + const BLASTriangleDesc& DstTri = DstDesc.pTriangles[Index]; + + CHECK_COPY_BLAS_ATTRIBS(SrcTri.MaxVertexCount == DstTri.MaxVertexCount, + "MaxVertexCount value (", SrcTri.MaxVertexCount, ") in source triangle description at index ", i, + " does not match MaxVertexCount value (", DstTri.MaxVertexCount, ") in the destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.VertexValueType == DstTri.VertexValueType, + "VertexValueType value (", GetValueTypeString(SrcTri.VertexValueType), ") in source triangle description at index ", i, + " does not match VertexValueType value (", GetValueTypeString(DstTri.VertexValueType), ") in destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.VertexComponentCount == DstTri.VertexComponentCount, + "VertexComponentCount value (", Uint32{SrcTri.VertexComponentCount}, ") in source triangle description at index ", i, + " does not match VertexComponentCount value (", Uint32{DstTri.VertexComponentCount}, ") in destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.MaxPrimitiveCount == DstTri.MaxPrimitiveCount, + "MaxPrimitiveCount value (", SrcTri.MaxPrimitiveCount, ") in source triangle description at index ", i, + " does not match MaxPrimitiveCount value (", DstTri.MaxPrimitiveCount, ") in destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.IndexType == DstTri.IndexType, + "IndexType value (", GetValueTypeString(SrcTri.IndexType), ") in source triangle description at index ", i, + " does not match IndexType value (", GetValueTypeString(DstTri.IndexType), ") in destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.AllowsTransforms == DstTri.AllowsTransforms, + "AllowsTransforms value (", (SrcTri.AllowsTransforms ? "true" : "false"), ") in source triangle description at index ", i, + " does not match AllowsTransforms value (", (DstTri.AllowsTransforms ? "true" : "false"), ") in destination description"); + } + + for (Uint32 i = 0; i < SrcDesc.BoxCount; ++i) + { + const BLASBoundingBoxDesc& SrcBox = SrcDesc.pBoxes[i]; + const Uint32 Index = Attribs.pDst->GetGeometryDescIndex(SrcBox.GeometryName); + if (Index == INVALID_INDEX) + { + LOG_ERROR_MESSAGE("Copy BLAS attribs are invalid: pSrc->GetDesc().pBoxes[", i, "].GeometryName ('", SrcBox.GeometryName, "') is not found in pDst"); + return false; + } + const BLASBoundingBoxDesc& DstBox = DstDesc.pBoxes[Index]; + + CHECK_COPY_BLAS_ATTRIBS(SrcBox.MaxBoxCount == DstBox.MaxBoxCount, + "MaxBoxCountt value (", SrcBox.MaxBoxCount, ") in source box description at index ", i, + " does not match MaxBoxCount value (", DstBox.MaxBoxCount, ") in destination description"); + } } } else if (Attribs.Mode == COPY_AS_MODE_COMPACT) @@ -617,7 +676,7 @@ bool VerifyCopyTLASAttribs(const CopyTLASAttribs& Attribs) auto& SrcDesc = Attribs.pSrc->GetDesc(); auto& DstDesc = Attribs.pDst->GetDesc(); - CHECK_COPY_TLAS_ATTRIBS(SrcDesc.MaxInstanceCount == DstDesc.MaxInstanceCount || SrcDesc.Flags == DstDesc.Flags, + CHECK_COPY_TLAS_ATTRIBS(SrcDesc.MaxInstanceCount == DstDesc.MaxInstanceCount && SrcDesc.Flags == DstDesc.Flags, "pDst must have been created with the same parameters as pSrc"); } else if (Attribs.Mode == COPY_AS_MODE_COMPACT) @@ -647,12 +706,13 @@ bool VerifyWriteBLASCompactedSizeAttribs(const IRenderDevice* pDevice, const Wri "pBLAS was not created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); CHECK_WRITE_BLAS_SIZE_ATTRIBS(Attribs.pDestBuffer != nullptr, "pDestBuffer must not be null"); - CHECK_WRITE_BLAS_SIZE_ATTRIBS(Attribs.DestBufferOffset + sizeof(Uint64) <= Attribs.pDestBuffer->GetDesc().uiSizeInBytes, - "pDestBuffer is too small"); + + const BufferDesc& DstDesc = Attribs.pDestBuffer->GetDesc(); + CHECK_WRITE_BLAS_SIZE_ATTRIBS(Attribs.DestBufferOffset + sizeof(Uint64) <= DstDesc.uiSizeInBytes, "pDestBuffer is too small"); if (pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_D3D12) { - CHECK_WRITE_BLAS_SIZE_ATTRIBS((Attribs.pDestBuffer->GetDesc().BindFlags & BIND_UNORDERED_ACCESS) == BIND_UNORDERED_ACCESS, + CHECK_WRITE_BLAS_SIZE_ATTRIBS((DstDesc.BindFlags & BIND_UNORDERED_ACCESS) == BIND_UNORDERED_ACCESS, "pDestBuffer must have been created with BIND_UNORDERED_ACCESS flag in Direct3D12"); } @@ -670,11 +730,13 @@ bool VerifyWriteTLASCompactedSizeAttribs(const IRenderDevice* pDevice, const Wri "pTLAS was not created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); CHECK_WRITE_TLAS_SIZE_ATTRIBS(Attribs.pDestBuffer != nullptr, "pDestBuffer must not be null"); - CHECK_WRITE_TLAS_SIZE_ATTRIBS(Attribs.DestBufferOffset + sizeof(Uint64) <= Attribs.pDestBuffer->GetDesc().uiSizeInBytes, "pDestBuffer is too small"); + + const BufferDesc& DstDesc = Attribs.pDestBuffer->GetDesc(); + CHECK_WRITE_TLAS_SIZE_ATTRIBS(Attribs.DestBufferOffset + sizeof(Uint64) <= DstDesc.uiSizeInBytes, "pDestBuffer is too small"); if (pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_D3D12) { - CHECK_WRITE_TLAS_SIZE_ATTRIBS((Attribs.pDestBuffer->GetDesc().BindFlags & BIND_UNORDERED_ACCESS) == BIND_UNORDERED_ACCESS, + CHECK_WRITE_TLAS_SIZE_ATTRIBS((DstDesc.BindFlags & BIND_UNORDERED_ACCESS) == BIND_UNORDERED_ACCESS, "pDestBuffer must have been created with BIND_UNORDERED_ACCESS flag"); } @@ -689,7 +751,8 @@ bool VerifyTraceRaysAttribs(const TraceRaysAttribs& Attribs) CHECK_TRACE_RAYS_ATTRIBS(Attribs.pSBT != nullptr, "pSBT must not be null"); #ifdef DILIGENT_DEVELOPMENT - CHECK_TRACE_RAYS_ATTRIBS(Attribs.pSBT->Verify(), "pSBT content is not valid"); + CHECK_TRACE_RAYS_ATTRIBS(Attribs.pSBT->Verify(SHADER_BINDING_VALIDATION_SHADER_ONLY | SHADER_BINDING_VALIDATION_TLAS), + "pSBT not all shaders are binded or instance to shader mapping are incorrect"); #endif // DILIGENT_DEVELOPMENT CHECK_TRACE_RAYS_ATTRIBS(Attribs.DimensionX != 0, "DimensionX must not be zero."); diff --git a/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp index c16d8473..12118e18 100644 --- a/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp @@ -47,8 +47,12 @@ public: BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, class RenderDeviceD3D12Impl* pDeviceD3D12, + const BottomLevelASDesc& Desc); + BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, const BottomLevelASDesc& Desc, - bool bIsDeviceInternal = false); + RESOURCE_STATE InitialState, + ID3D12Resource* pd3d12BLAS); ~BottomLevelASD3D12Impl(); IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BottomLevelASD3D12, TBottomLevelASBase); diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp index ad48b876..5c4ad160 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp @@ -133,6 +133,18 @@ public: RESOURCE_STATE InitialState, IBuffer** ppBuffer) override final; + /// Implementation of IRenderDeviceD3D12::CreateBLASFromD3DResource(). + virtual void DILIGENT_CALL_TYPE CreateBLASFromD3DResource(ID3D12Resource* pd3d12BLAS, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + IBottomLevelAS** ppBLAS) override final; + + /// Implementation of IRenderDeviceD3D12::CreateTLASFromD3DResource(). + virtual void DILIGENT_CALL_TYPE CreateTLASFromD3DResource(ID3D12Resource* pd3d12TLAS, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ITopLevelAS** ppTLAS) override final; + DescriptorHeapAllocation AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1); DescriptorHeapAllocation AllocateGPUDescriptors(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1); @@ -180,7 +192,7 @@ public: const Uint32 ShaderGroupHandleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; const Uint32 MaxShaderRecordStride = D3D12_RAYTRACING_MAX_SHADER_RECORD_STRIDE; const Uint32 ShaderGroupBaseAlignment = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; - const Uint32 MaxDrawMeshTasksCount = 64000; + const Uint32 MaxDrawMeshTasksCount = 64000; // from specs: https://microsoft.github.io/DirectX-Specs/d3d/MeshShader.html#dispatchmesh-api ShaderVersion MaxShaderVersion; }; diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp index 537f240a..ca1442c5 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp @@ -33,6 +33,7 @@ #include "ShaderBindingTableD3D12.h" #include "RenderDeviceD3D12.h" #include "ShaderBindingTableBase.hpp" +#include "TopLevelASD3D12Impl.hpp" #include "D3D12ResourceBase.hpp" #include "RenderDeviceD3D12Impl.hpp" #include "PipelineStateD3D12Impl.hpp" @@ -41,10 +42,10 @@ namespace Diligent { /// Shader binding table object implementation in Direct3D12 backend. -class ShaderBindingTableD3D12Impl final : public ShaderBindingTableBase<IShaderBindingTableD3D12, PipelineStateD3D12Impl, RenderDeviceD3D12Impl>, public D3D12ResourceBase +class ShaderBindingTableD3D12Impl final : public ShaderBindingTableBase<IShaderBindingTableD3D12, PipelineStateD3D12Impl, TopLevelASD3D12Impl, RenderDeviceD3D12Impl>, public D3D12ResourceBase { public: - using TShaderBindingTableBase = ShaderBindingTableBase<IShaderBindingTableD3D12, PipelineStateD3D12Impl, RenderDeviceD3D12Impl>; + using TShaderBindingTableBase = ShaderBindingTableBase<IShaderBindingTableD3D12, PipelineStateD3D12Impl, TopLevelASD3D12Impl, RenderDeviceD3D12Impl>; ShaderBindingTableD3D12Impl(IReferenceCounters* pRefCounters, class RenderDeviceD3D12Impl* pDeviceD3D12, @@ -53,10 +54,6 @@ public: ~ShaderBindingTableD3D12Impl(); virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; - - virtual void DILIGENT_CALL_TYPE ResetHitGroups(Uint32 HitShadersPerInstance) override; - - virtual void DILIGENT_CALL_TYPE BindAll(const BindAllAttribs& Attribs) override; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp index fe161157..58a8141d 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp @@ -297,6 +297,8 @@ public: SHADER_TYPE GetShaderType() const { return m_ShaderType; } + bool IsCompatibleWith(const ShaderResourceLayoutD3D12& ResLayout) const; + private: const D3D12Resource& GetAssignedSampler(const D3D12Resource& TexSrv) const; D3D12Resource& GetAssignedSampler(const D3D12Resource& TexSrv); diff --git a/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp index 3fa15e5e..522fd426 100644 --- a/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp @@ -48,8 +48,12 @@ public: TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, class RenderDeviceD3D12Impl* pDeviceD3D12, + const TopLevelASDesc& Desc); + TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, const TopLevelASDesc& Desc, - bool bIsDeviceInternal = false); + RESOURCE_STATE InitialState, + ID3D12Resource* pd3d12TLAS); ~TopLevelASD3D12Impl(); IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelASD3D12, TTopLevelASBase); diff --git a/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h b/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h index cd315d3e..bec8d338 100644 --- a/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h @@ -75,6 +75,7 @@ DILIGENT_END_INTERFACE // clang-format off # define IPipelineStateD3D12_GetD3D12PipelineState(This) CALL_IFACE_METHOD(PipelineStateD3D12, GetD3D12PipelineState, This) +# define IPipelineStateD3D12_GetD3D12StateObject(This) CALL_IFACE_METHOD(PipelineStateD3D12, GetD3D12StateObject, This) # define IPipelineStateD3D12_GetD3D12RootSignature(This) CALL_IFACE_METHOD(PipelineStateD3D12, GetD3D12RootSignature, This) // clang-format on diff --git a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h index 136f7307..8d8d1fba 100644 --- a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h @@ -99,6 +99,38 @@ DILIGENT_BEGIN_INTERFACE(IRenderDeviceD3D12, IRenderDevice) const BufferDesc REF BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer) PURE; + + /// Creates a bottom-level AS object from native d3d12 resoruce + + /// \param [in] pd3d12BLAS - Pointer to the native d3d12 acceleration structure resource + /// \param [in] Desc - Bottom-level AS description. + /// \param [in] InitialState - Initial BLAS state. Can be RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_BUILD_AS_READ, RESOURCE_STATE_BUILD_AS_WRITE. + /// See Diligent::RESOURCE_STATE. + /// \param [out] ppBLAS - Address of the memory location where the pointer to the + /// bottom-level AS interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + VIRTUAL void METHOD(CreateBLASFromD3DResource)(THIS_ + ID3D12Resource* pd3d12BLAS, + const BottomLevelASDesc REF Desc, + RESOURCE_STATE InitialState, + IBottomLevelAS** ppBLAS) PURE; + + /// Creates a top-level AS object from native d3d12 resoruce + + /// \param [in] pd3d12TLAS - Pointer to the native d3d12 acceleration structure resource + /// \param [in] Desc - Top-level AS description. + /// \param [in] InitialState - Initial TLAS state. Can be RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_BUILD_AS_READ, RESOURCE_STATE_BUILD_AS_WRITE, RESOURCE_STATE_RAY_TRACING. + /// See Diligent::RESOURCE_STATE. + /// \param [out] ppTLAS - Address of the memory location where the pointer to the + /// top-level AS interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + VIRTUAL void METHOD(CreateTLASFromD3DResource)(THIS_ + ID3D12Resource* pd3d12TLAS, + const TopLevelASDesc REF Desc, + RESOURCE_STATE InitialState, + ITopLevelAS** ppTLAS) PURE; }; DILIGENT_END_INTERFACE @@ -114,6 +146,8 @@ DILIGENT_END_INTERFACE # define IRenderDeviceD3D12_IsFenceSignaled(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, IsFenceSignaled, This, __VA_ARGS__) # define IRenderDeviceD3D12_CreateTextureFromD3DResource(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, CreateTextureFromD3DResource, This, __VA_ARGS__) # define IRenderDeviceD3D12_CreateBufferFromD3DResource(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, CreateBufferFromD3DResource, This, __VA_ARGS__) +# define IRenderDeviceD3D12_CreateBLASFromD3DResource(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, CreateBLASFromD3DResource, This, __VA_ARGS__) +# define IRenderDeviceD3D12_CreateTLASFromD3DResource(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, CreateTLASFromD3DResource, This, __VA_ARGS__) // clang-format on diff --git a/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp index fa82ee9a..d2e119b3 100644 --- a/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp @@ -38,9 +38,8 @@ namespace Diligent BottomLevelASD3D12Impl::BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, class RenderDeviceD3D12Impl* pDeviceD3D12, - const BottomLevelASDesc& Desc, - bool bIsDeviceInternal) : - TBottomLevelASBase{pRefCounters, pDeviceD3D12, Desc, bIsDeviceInternal} + const BottomLevelASDesc& Desc) : + TBottomLevelASBase{pRefCounters, pDeviceD3D12, Desc} { auto* pd3d12Device = pDeviceD3D12->GetD3D12Device5(); UINT64 ResultDataMaxSizeInBytes = 0; @@ -66,15 +65,15 @@ BottomLevelASD3D12Impl::BottomLevelASD3D12Impl(IReferenceCounters* pRef dst.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; dst.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; + dst.Triangles.IndexCount = src.IndexType == VT_UNDEFINED ? 0 : src.MaxPrimitiveCount * 3; + dst.Triangles.IndexFormat = ValueTypeToIndexType(src.IndexType); + dst.Triangles.IndexBuffer = 0; + dst.Triangles.Transform3x4 = 0; dst.Triangles.VertexBuffer.StartAddress = 0; dst.Triangles.VertexBuffer.StrideInBytes = 0; + dst.Triangles.VertexCount = src.MaxVertexCount; dst.Triangles.VertexFormat = TypeToRayTracingVertexFormat(src.VertexValueType, src.VertexComponentCount); VERIFY(dst.Triangles.VertexFormat != DXGI_FORMAT_UNKNOWN, "Unsupported combination of vertex value type and component count"); - dst.Triangles.VertexCount = src.MaxVertexCount; - dst.Triangles.IndexCount = src.IndexType == VT_UNDEFINED ? 0 : src.MaxPrimitiveCount * 3; - dst.Triangles.IndexFormat = ValueTypeToIndexType(src.IndexType); - dst.Triangles.IndexBuffer = 0; - dst.Triangles.Transform3x4 = 0; MaxPrimitiveCount += src.MaxPrimitiveCount; } @@ -157,6 +156,17 @@ BottomLevelASD3D12Impl::BottomLevelASD3D12Impl(IReferenceCounters* pRef SetState(RESOURCE_STATE_BUILD_AS_READ); } +BottomLevelASD3D12Impl::BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ID3D12Resource* pd3d12BLAS) : + TBottomLevelASBase{pRefCounters, pDeviceD3D12, Desc} +{ + m_pd3d12Resource = pd3d12BLAS; + SetState(InitialState); +} + BottomLevelASD3D12Impl::~BottomLevelASD3D12Impl() { // D3D12 object can only be destroyed when it is no longer used by the GPU diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index c78976ea..3d1c836f 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -2277,14 +2277,14 @@ void DeviceContextD3D12Impl::BuildBLAS(const BuildBLASAttribs& Attribs) if (!TDeviceContextBase::BuildBLAS(Attribs, 0)) return; - auto* const pBLASD12 = ValidatedCast<BottomLevelASD3D12Impl>(Attribs.pBLAS); - auto* const pScratchD12 = ValidatedCast<BufferD3D12Impl>(Attribs.pScratchBuffer); - const auto& BLASDesc = pBLASD12->GetDesc(); + auto* const pBLASD3D12 = ValidatedCast<BottomLevelASD3D12Impl>(Attribs.pBLAS); + auto* const pScratchD3D12 = ValidatedCast<BufferD3D12Impl>(Attribs.pScratchBuffer); + const auto& BLASDesc = pBLASD3D12->GetDesc(); auto& CmdCtx = GetCmdContext(); const char* OpName = "Build BottomLevelAS (DeviceContextD3D12Impl::BuildBLAS)"; - TransitionOrVerifyBLASState(CmdCtx, *pBLASD12, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); - TransitionOrVerifyBufferState(CmdCtx, *pScratchD12, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + TransitionOrVerifyBLASState(CmdCtx, *pBLASD3D12, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + TransitionOrVerifyBufferState(CmdCtx, *pScratchD3D12, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC d3d12BuildASDesc = {}; D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& d3d12BuildASInputs = d3d12BuildASDesc.Inputs; @@ -2293,19 +2293,21 @@ void DeviceContextD3D12Impl::BuildBLAS(const BuildBLASAttribs& Attribs) if (Attribs.pTriangleData != nullptr) { Geometries.resize(Attribs.TriangleDataCount); + pBLASD3D12->SetActualGeometryCount(Attribs.TriangleDataCount); for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i) { const auto& SrcTris = Attribs.pTriangleData[i]; - Uint32 GeoIdx = pBLASD12->GetGeometryIndex(SrcTris.GeometryName); + Uint32 Idx = i; + Uint32 GeoIdx = pBLASD3D12->UpdateGeometryIndex(SrcTris.GeometryName, Idx, Attribs.Update); - if (GeoIdx >= Geometries.size()) + if (GeoIdx == INVALID_INDEX || Idx == INVALID_INDEX) { UNEXPECTED("Failed to find geometry by name"); continue; } - auto& d3d12Geo = Geometries[GeoIdx]; + auto& d3d12Geo = Geometries[Idx]; auto& d3d12Tris = d3d12Geo.Triangles; const auto& TriDesc = BLASDesc.pTriangles[GeoIdx]; @@ -2315,11 +2317,11 @@ void DeviceContextD3D12Impl::BuildBLAS(const BuildBLASAttribs& Attribs) auto* const pVB = ValidatedCast<BufferD3D12Impl>(SrcTris.pVertexBuffer); // vertex format in SrcTris may be undefined, so use vertex format from description - d3d12Tris.VertexFormat = TypeToRayTracingVertexFormat(TriDesc.VertexValueType, TriDesc.VertexComponentCount); - VERIFY(d3d12Tris.VertexFormat != DXGI_FORMAT_UNKNOWN, "Unsupported combination of vertex value type and component count"); - d3d12Tris.VertexCount = SrcTris.VertexCount; d3d12Tris.VertexBuffer.StartAddress = pVB->GetGPUAddress() + SrcTris.VertexOffset; d3d12Tris.VertexBuffer.StrideInBytes = SrcTris.VertexStride; + d3d12Tris.VertexCount = SrcTris.VertexCount; + d3d12Tris.VertexFormat = TypeToRayTracingVertexFormat(TriDesc.VertexValueType, TriDesc.VertexComponentCount); + VERIFY(d3d12Tris.VertexFormat != DXGI_FORMAT_UNKNOWN, "Unsupported combination of vertex value type and component count"); TransitionOrVerifyBufferState(CmdCtx, *pVB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); @@ -2358,19 +2360,21 @@ void DeviceContextD3D12Impl::BuildBLAS(const BuildBLASAttribs& Attribs) else if (Attribs.pBoxData != nullptr) { Geometries.resize(Attribs.BoxDataCount); + pBLASD3D12->SetActualGeometryCount(Attribs.BoxDataCount); for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i) { const auto& SrcBoxes = Attribs.pBoxData[i]; - Uint32 GeoIdx = pBLASD12->GetGeometryIndex(SrcBoxes.GeometryName); + Uint32 Idx = i; + Uint32 GeoIdx = pBLASD3D12->UpdateGeometryIndex(SrcBoxes.GeometryName, Idx, Attribs.Update); - if (GeoIdx >= Geometries.size()) + if (GeoIdx == INVALID_INDEX || Idx == INVALID_INDEX) { UNEXPECTED("Failed to find geometry by name"); continue; } - auto& d3d12Geo = Geometries[GeoIdx]; + auto& d3d12Geo = Geometries[Idx]; auto& d3d12AABs = d3d12Geo.AABBs; d3d12Geo.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; @@ -2393,10 +2397,16 @@ void DeviceContextD3D12Impl::BuildBLAS(const BuildBLASAttribs& Attribs) d3d12BuildASInputs.NumDescs = static_cast<UINT>(Geometries.size()); d3d12BuildASInputs.pGeometryDescs = Geometries.data(); - d3d12BuildASDesc.DestAccelerationStructureData = pBLASD12->GetGPUAddress(); - d3d12BuildASDesc.ScratchAccelerationStructureData = pScratchD12->GetGPUAddress() + Attribs.ScratchBufferOffset; + d3d12BuildASDesc.DestAccelerationStructureData = pBLASD3D12->GetGPUAddress(); + d3d12BuildASDesc.ScratchAccelerationStructureData = pScratchD3D12->GetGPUAddress() + Attribs.ScratchBufferOffset; d3d12BuildASDesc.SourceAccelerationStructureData = 0; + if (Attribs.Update) + { + d3d12BuildASInputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE; + d3d12BuildASDesc.SourceAccelerationStructureData = d3d12BuildASDesc.DestAccelerationStructureData; + } + DEV_CHECK_ERR(d3d12BuildASDesc.ScratchAccelerationStructureData % D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT == 0, "Scratch data address is not properly aligned"); @@ -2404,7 +2414,7 @@ void DeviceContextD3D12Impl::BuildBLAS(const BuildBLASAttribs& Attribs) ++m_State.NumCommands; #ifdef DILIGENT_DEVELOPMENT - pBLASD12->UpdateVersion(); + pBLASD3D12->UpdateVersion(); #endif } @@ -2415,16 +2425,25 @@ void DeviceContextD3D12Impl::BuildTLAS(const BuildTLASAttribs& Attribs) static_assert(TLAS_INSTANCE_DATA_SIZE == sizeof(D3D12_RAYTRACING_INSTANCE_DESC), "Value in TLAS_INSTANCE_DATA_SIZE doesn't match the actual instance description size"); - auto* pTLASD12 = ValidatedCast<TopLevelASD3D12Impl>(Attribs.pTLAS); - auto* pScratchD12 = ValidatedCast<BufferD3D12Impl>(Attribs.pScratchBuffer); - auto* pInstancesD12 = ValidatedCast<BufferD3D12Impl>(Attribs.pInstanceBuffer); + auto* pTLASD3D12 = ValidatedCast<TopLevelASD3D12Impl>(Attribs.pTLAS); + auto* pScratchD3D12 = ValidatedCast<BufferD3D12Impl>(Attribs.pScratchBuffer); + auto* pInstancesD3D12 = ValidatedCast<BufferD3D12Impl>(Attribs.pInstanceBuffer); auto& CmdCtx = GetCmdContext(); const char* OpName = "Build TopLevelAS (DeviceContextD3D12Impl::BuildTLAS)"; - TransitionOrVerifyTLASState(CmdCtx, *pTLASD12, Attribs.TLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); - TransitionOrVerifyBufferState(CmdCtx, *pScratchD12, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + TransitionOrVerifyTLASState(CmdCtx, *pTLASD3D12, Attribs.TLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + TransitionOrVerifyBufferState(CmdCtx, *pScratchD3D12, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); - pTLASD12->SetInstanceData(Attribs.pInstances, Attribs.InstanceCount, Attribs.HitShadersPerInstance); + if (Attribs.Update) + { + if (!pTLASD3D12->UpdateInstances(Attribs.pInstances, Attribs.InstanceCount, Attribs.BaseContributionToHitGroupIndex, Attribs.HitShadersPerInstance, Attribs.BindingMode)) + return; + } + else + { + if (!pTLASD3D12->SetInstanceData(Attribs.pInstances, Attribs.InstanceCount, Attribs.BaseContributionToHitGroupIndex, Attribs.HitShadersPerInstance, Attribs.BindingMode)) + return; + } // copy instance data into instance buffer { @@ -2433,38 +2452,52 @@ void DeviceContextD3D12Impl::BuildTLAS(const BuildTLASAttribs& Attribs) for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) { - const auto& Inst = Attribs.pInstances[i]; - auto& d3d12Inst = static_cast<D3D12_RAYTRACING_INSTANCE_DESC*>(TmpSpace.CPUAddress)[i]; - auto* const pBLASD12 = ValidatedCast<BottomLevelASD3D12Impl>(Inst.pBLAS); + const auto& Inst = Attribs.pInstances[i]; + const auto InstDesc = pTLASD3D12->GetInstanceDesc(Inst.InstanceName); + + if (InstDesc.InstanceIndex >= Attribs.InstanceCount) + { + UNEXPECTED("Failed to find instance by name"); + return; + } + + auto& d3d12Inst = static_cast<D3D12_RAYTRACING_INSTANCE_DESC*>(TmpSpace.CPUAddress)[InstDesc.InstanceIndex]; + auto* pBLASD3D12 = ValidatedCast<BottomLevelASD3D12Impl>(Inst.pBLAS); static_assert(sizeof(d3d12Inst.Transform) == sizeof(Inst.Transform), "size mismatch"); std::memcpy(&d3d12Inst.Transform, Inst.Transform.data, sizeof(d3d12Inst.Transform)); d3d12Inst.InstanceID = Inst.CustomId; - d3d12Inst.InstanceContributionToHitGroupIndex = pTLASD12->GetInstanceDesc(Inst.InstanceName).ContributionToHitGroupIndex; + d3d12Inst.InstanceContributionToHitGroupIndex = InstDesc.ContributionToHitGroupIndex; d3d12Inst.InstanceMask = Inst.Mask; d3d12Inst.Flags = InstanceFlagsToD3D12RTInstanceFlags(Inst.Flags); - d3d12Inst.AccelerationStructure = pBLASD12->GetGPUAddress(); + d3d12Inst.AccelerationStructure = pBLASD3D12->GetGPUAddress(); - TransitionOrVerifyBLASState(CmdCtx, *pBLASD12, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyBLASState(CmdCtx, *pBLASD3D12, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); } - UpdateBufferRegion(pInstancesD12, TmpSpace, Attribs.InstanceBufferOffset, Size, Attribs.InstanceBufferTransitionMode); + UpdateBufferRegion(pInstancesD3D12, TmpSpace, Attribs.InstanceBufferOffset, Size, Attribs.InstanceBufferTransitionMode); } - TransitionOrVerifyBufferState(CmdCtx, *pInstancesD12, Attribs.InstanceBufferTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyBufferState(CmdCtx, *pInstancesD3D12, Attribs.InstanceBufferTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC d3d12BuildASDesc = {}; D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& d3d12BuildASInputs = d3d12BuildASDesc.Inputs; d3d12BuildASInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - d3d12BuildASInputs.Flags = BuildASFlagsToD3D12ASBuildFlags(pTLASD12->GetDesc().Flags); + d3d12BuildASInputs.Flags = BuildASFlagsToD3D12ASBuildFlags(pTLASD3D12->GetDesc().Flags); d3d12BuildASInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; d3d12BuildASInputs.NumDescs = Attribs.InstanceCount; - d3d12BuildASInputs.InstanceDescs = pInstancesD12->GetGPUAddress() + Attribs.InstanceBufferOffset; + d3d12BuildASInputs.InstanceDescs = pInstancesD3D12->GetGPUAddress() + Attribs.InstanceBufferOffset; - d3d12BuildASDesc.DestAccelerationStructureData = pTLASD12->GetGPUAddress(); - d3d12BuildASDesc.ScratchAccelerationStructureData = pScratchD12->GetGPUAddress() + Attribs.ScratchBufferOffset; + d3d12BuildASDesc.DestAccelerationStructureData = pTLASD3D12->GetGPUAddress(); + d3d12BuildASDesc.ScratchAccelerationStructureData = pScratchD3D12->GetGPUAddress() + Attribs.ScratchBufferOffset; d3d12BuildASDesc.SourceAccelerationStructureData = 0; + if (Attribs.Update) + { + d3d12BuildASInputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE; + d3d12BuildASDesc.SourceAccelerationStructureData = d3d12BuildASDesc.DestAccelerationStructureData; + } + DEV_CHECK_ERR(d3d12BuildASInputs.InstanceDescs % D3D12_RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT == 0, "Instance data address is not properly aligned"); DEV_CHECK_ERR(d3d12BuildASDesc.ScratchAccelerationStructureData % D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT == 0, @@ -2486,7 +2519,8 @@ void DeviceContextD3D12Impl::CopyBLAS(const CopyBLASAttribs& Attribs) // Dst BLAS description has specified CompactedSize, but doesn't have specified pTriangles and pBoxes. // We should copy geometries because it required for SBT to map geometry name to hit group. - pDstD3D12->CopyDescription(*pSrcD3D12); + pDstD3D12->CopyGeometryDescription(*pSrcD3D12); + pDstD3D12->SetActualGeometryCount(pSrcD3D12->GetActualGeometryCount()); const char* OpName = "Copy BottomLevelAS (DeviceContextD3D12Impl::CopyBLAS)"; TransitionOrVerifyBLASState(CmdCtx, *pSrcD3D12, Attribs.SrcTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); @@ -2579,16 +2613,16 @@ void DeviceContextD3D12Impl::TraceRays(const TraceRaysAttribs& Attribs) VERIFY_EXPR((Attribs.DimensionX * Attribs.DimensionY * Attribs.DimensionZ) <= D3D12_RAYTRACING_MAX_RAY_GENERATION_SHADER_THREADS); - auto& CmdCtx = GetCmdContext().AsGraphicsContext4(); - auto* pSBTD12 = ValidatedCast<ShaderBindingTableD3D12Impl>(Attribs.pSBT); - IBuffer* pBuffer = nullptr; + auto& CmdCtx = GetCmdContext().AsGraphicsContext4(); + auto* pSBTD3D12 = ValidatedCast<ShaderBindingTableD3D12Impl>(Attribs.pSBT); + IBuffer* pBuffer = nullptr; ShaderBindingTableD3D12Impl::BindingTable RayGenShaderRecord = {}; ShaderBindingTableD3D12Impl::BindingTable MissShaderTable = {}; ShaderBindingTableD3D12Impl::BindingTable HitGroupTable = {}; ShaderBindingTableD3D12Impl::BindingTable CallableShaderTable = {}; - pSBTD12->GetData(pBuffer, RayGenShaderRecord, MissShaderTable, HitGroupTable, CallableShaderTable); + pSBTD3D12->GetData(pBuffer, RayGenShaderRecord, MissShaderTable, HitGroupTable, CallableShaderTable); auto* pBufferD3D12 = ValidatedCast<BufferD3D12Impl>(pBuffer); diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp index 1a12f25b..be30c978 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -729,16 +729,17 @@ void PipelineStateD3D12Impl::InitResourceLayouts(const PipelineStateCreateInfo& auto pd3d12Device = GetDevice()->GetD3D12Device(); const auto& ResourceLayout = m_Desc.ResourceLayout; - // AZ TODO -#if 0 //def DILIGENT_DEVELOPMENT +#ifdef DILIGENT_DEVELOPMENT { - const ShaderResources* pResources[MAX_SHADERS_IN_PIPELINE] = {}; + std::vector<const ShaderResources*> Resources; for (size_t s = 0; s < ShaderStages.size(); ++s) { - const auto* pShader = ShaderStages[s].Shaders[0]; - pResources[s] = &(*pShader->GetShaderResources()); + for (auto* pShader : ShaderStages[s].Shaders) + { + Resources.push_back(&(*pShader->GetShaderResources())); + } } - ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, GetNumShaderStages(), + ShaderResources::DvpVerifyResourceLayout(ResourceLayout, Resources.data(), static_cast<Uint32>(Resources.size()), (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS) == 0); } @@ -832,8 +833,7 @@ bool PipelineStateD3D12Impl::IsCompatibleWith(const IPipelineState* pPSO) const auto IsSameRootSignature = m_RootSig.IsSameAs(pPSOD3D12->m_RootSig); - // AZ TODO -#if 0 //def DILIGENT_DEBUG +#ifdef DILIGENT_DEBUG { bool IsCompatibleShaders = true; if (GetNumShaderStages() != pPSOD3D12->GetNumShaderStages()) @@ -849,8 +849,8 @@ bool PipelineStateD3D12Impl::IsCompatibleWith(const IPipelineState* pPSO) const break; } - const auto& Res0 = GetShaderResLayout(s).GetResources(); - const auto& Res1 = pPSOD3D12->GetShaderResLayout(s).GetResources(); + const auto& Res0 = GetShaderResLayout(s); + const auto& Res1 = pPSOD3D12->GetShaderResLayout(s); if (!Res0.IsCompatibleWith(Res1)) { IsCompatibleShaders = false; diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 9ea84f06..76bf71c4 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -724,6 +724,19 @@ void RenderDeviceD3D12Impl::CreateFramebuffer(const FramebufferDesc& Desc, IFram }); } +void RenderDeviceD3D12Impl::CreateBLASFromD3DResource(ID3D12Resource* pd3d12BLAS, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + IBottomLevelAS** ppBLAS) +{ + CreateDeviceObject("buffer", Desc, ppBLAS, + [&]() // + { + BottomLevelASD3D12Impl* pBottomLevelASD3D12{NEW_RC_OBJ(m_BLASAllocator, "BottomLevelASD3D12Impl instance", BottomLevelASD3D12Impl)(this, Desc, InitialState, pd3d12BLAS)}; + pBottomLevelASD3D12->QueryInterface(IID_BottomLevelAS, reinterpret_cast<IObject**>(ppBLAS)); + OnCreateDeviceObject(pBottomLevelASD3D12); + }); +} void RenderDeviceD3D12Impl::CreateBLAS(const BottomLevelASDesc& Desc, IBottomLevelAS** ppBLAS) @@ -731,9 +744,23 @@ void RenderDeviceD3D12Impl::CreateBLAS(const BottomLevelASDesc& Desc, CreateDeviceObject("BottomLevelAS", Desc, ppBLAS, [&]() // { - BottomLevelASD3D12Impl* pBottomLevelASVk(NEW_RC_OBJ(m_BLASAllocator, "BottomLevelASD3D12Impl instance", BottomLevelASD3D12Impl)(this, Desc)); - pBottomLevelASVk->QueryInterface(IID_BottomLevelAS, reinterpret_cast<IObject**>(ppBLAS)); - OnCreateDeviceObject(pBottomLevelASVk); + BottomLevelASD3D12Impl* pBottomLevelASD3D12(NEW_RC_OBJ(m_BLASAllocator, "BottomLevelASD3D12Impl instance", BottomLevelASD3D12Impl)(this, Desc)); + pBottomLevelASD3D12->QueryInterface(IID_BottomLevelAS, reinterpret_cast<IObject**>(ppBLAS)); + OnCreateDeviceObject(pBottomLevelASD3D12); + }); +} + +void RenderDeviceD3D12Impl::CreateTLASFromD3DResource(ID3D12Resource* pd3d12TLAS, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ITopLevelAS** ppTLAS) +{ + CreateDeviceObject("TopLevelAS", Desc, ppTLAS, + [&]() // + { + TopLevelASD3D12Impl* pTopLevelASD3D12{NEW_RC_OBJ(m_TLASAllocator, "TopLevelASD3D12Impl instance", TopLevelASD3D12Impl)(this, Desc, InitialState, pd3d12TLAS)}; + pTopLevelASD3D12->QueryInterface(IID_TopLevelAS, reinterpret_cast<IObject**>(ppTLAS)); + OnCreateDeviceObject(pTopLevelASD3D12); }); } @@ -743,9 +770,9 @@ void RenderDeviceD3D12Impl::CreateTLAS(const TopLevelASDesc& Desc, CreateDeviceObject("TopLevelAS", Desc, ppTLAS, [&]() // { - TopLevelASD3D12Impl* pTopLevelASVk(NEW_RC_OBJ(m_TLASAllocator, "TopLevelASD3D12Impl instance", TopLevelASD3D12Impl)(this, Desc)); - pTopLevelASVk->QueryInterface(IID_TopLevelAS, reinterpret_cast<IObject**>(ppTLAS)); - OnCreateDeviceObject(pTopLevelASVk); + TopLevelASD3D12Impl* pTopLevelASD3D12(NEW_RC_OBJ(m_TLASAllocator, "TopLevelASD3D12Impl instance", TopLevelASD3D12Impl)(this, Desc)); + pTopLevelASD3D12->QueryInterface(IID_TopLevelAS, reinterpret_cast<IObject**>(ppTLAS)); + OnCreateDeviceObject(pTopLevelASD3D12); }); } @@ -755,9 +782,9 @@ void RenderDeviceD3D12Impl::CreateSBT(const ShaderBindingTableDesc& Desc, CreateDeviceObject("ShaderBindingTable", Desc, ppSBT, [&]() // { - ShaderBindingTableD3D12Impl* pSBTVk(NEW_RC_OBJ(m_SBTAllocator, "ShaderBindingTableD3D12Impl instance", ShaderBindingTableD3D12Impl)(this, Desc)); - pSBTVk->QueryInterface(IID_ShaderBindingTable, reinterpret_cast<IObject**>(ppSBT)); - OnCreateDeviceObject(pSBTVk); + ShaderBindingTableD3D12Impl* pSBTD3D12(NEW_RC_OBJ(m_SBTAllocator, "ShaderBindingTableD3D12Impl instance", ShaderBindingTableD3D12Impl)(this, Desc)); + pSBTD3D12->QueryInterface(IID_ShaderBindingTable, reinterpret_cast<IObject**>(ppSBT)); + OnCreateDeviceObject(pSBTD3D12); }); } diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp index 8a8bfd4d..2ac15372 100644 --- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp @@ -1154,10 +1154,10 @@ ID3D12RootSignature* LocalRootSignature::Create(ID3D12Device* pDevice) CComPtr<ID3DBlob> signature; auto hr = D3D12SerializeRootSignature(&d3d12RootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr); - CHECK_D3D_RESULT_THROW(hr, "Failed to serialize root signature"); + CHECK_D3D_RESULT_THROW(hr, "Failed to serialize local root signature"); hr = pDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_pd3d12RootSignature)); - CHECK_D3D_RESULT_THROW(hr, "Failed to create D3D12 root signature"); + CHECK_D3D_RESULT_THROW(hr, "Failed to create D3D12 local root signature"); return m_pd3d12RootSignature; } diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp index ac67ba57..0e15bd4f 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp @@ -52,14 +52,4 @@ ShaderBindingTableD3D12Impl::~ShaderBindingTableD3D12Impl() IMPLEMENT_QUERY_INTERFACE(ShaderBindingTableD3D12Impl, IID_ShaderBindingTableD3D12, TShaderBindingTableBase) -void ShaderBindingTableD3D12Impl::ResetHitGroups(Uint32 HitShadersPerInstance) -{ - // AZ TODO -} - -void ShaderBindingTableD3D12Impl::BindAll(const BindAllAttribs& Attribs) -{ - // AZ TODO -} - } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp index 6218fbd3..5923797c 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp @@ -1104,4 +1104,21 @@ bool ShaderResourceLayoutD3D12::dvpVerifyBindings(const ShaderResourceCacheD3D12 } #endif +bool ShaderResourceLayoutD3D12::IsCompatibleWith(const ShaderResourceLayoutD3D12& ResLayout) const +{ + if (GetTotalResourceCount() != ResLayout.GetTotalResourceCount()) + return false; + + for (Uint32 i = 0; i < GetTotalResourceCount(); ++i) + { + const auto& lRes = GetResource(i); + const auto& rRes = ResLayout.GetResource(i); + + if (!lRes.Attribs.IsCompatibleWith(rRes.Attribs)) + return false; + } + + return true; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp index 51dadde1..dff2dcfb 100644 --- a/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp @@ -38,9 +38,8 @@ namespace Diligent TopLevelASD3D12Impl::TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, class RenderDeviceD3D12Impl* pDeviceD3D12, - const TopLevelASDesc& Desc, - bool bIsDeviceInternal) : - TTopLevelASBase{pRefCounters, pDeviceD3D12, Desc, bIsDeviceInternal} + const TopLevelASDesc& Desc) : + TTopLevelASBase{pRefCounters, pDeviceD3D12, Desc} { auto* pd3d12Device = pDeviceD3D12->GetD3D12Device5(); UINT64 ResultDataMaxSizeInBytes = 0; @@ -115,6 +114,17 @@ TopLevelASD3D12Impl::TopLevelASD3D12Impl(IReferenceCounters* pRefCounte SetState(RESOURCE_STATE_BUILD_AS_READ); } +TopLevelASD3D12Impl::TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ID3D12Resource* pd3d12TLAS) : + TTopLevelASBase{pRefCounters, pDeviceD3D12, Desc} +{ + m_pd3d12Resource = pd3d12TLAS; + SetState(InitialState); +} + TopLevelASD3D12Impl::~TopLevelASD3D12Impl() { // D3D12 object can only be destroyed when it is no longer used by the GPU diff --git a/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp b/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp index d0691bd2..09d27372 100644 --- a/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp +++ b/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp @@ -236,15 +236,16 @@ void ShaderResources::DvpVerifyResourceLayout(const PipelineResourceLayoutDesc& std::string ShadersStr; while (ShaderStages != SHADER_TYPE_UNKNOWN) { - const auto ShaderType = ShaderStages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(ShaderStages) - 1)); - const char* ShaderName = nullptr; + const auto ShaderType = ShaderStages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(ShaderStages) - 1)); + String ShaderName; for (Uint32 s = 0; s < NumShaders; ++s) { const auto& Resources = *pShaderResources[s]; if ((ShaderStages & Resources.GetShaderType()) != 0) { - ShaderName = Resources.GetShaderName(); - break; + if (ShaderName.size()) + ShaderName += ", "; + ShaderName += Resources.GetShaderName(); } } @@ -252,10 +253,10 @@ void ShaderResources::DvpVerifyResourceLayout(const PipelineResourceLayoutDesc& ShadersStr.append(", "); ShadersStr.append(GetShaderTypeLiteralName(ShaderType)); ShadersStr.append(" ("); - if (ShaderName) + if (ShaderName.size()) { ShadersStr.push_back('\''); - ShadersStr.append(ShaderName ? ShaderName : "<Not enabled in PSO>"); + ShadersStr.append(ShaderName); ShadersStr.push_back('\''); } else diff --git a/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp index 1a4eb2c1..85665f2c 100644 --- a/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp @@ -46,8 +46,12 @@ public: BottomLevelASVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, - const BottomLevelASDesc& Desc, - bool bIsDeviceInternal = false); + const BottomLevelASDesc& Desc); + BottomLevelASVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pRenderDeviceVk, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + VkAccelerationStructureKHR vkBLAS); ~BottomLevelASVkImpl(); /// Implementation of IBottomLevelAS::GetNativeHandle() in Vulkan backend. diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index 8680b819..2aaf4c69 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp @@ -151,6 +151,18 @@ public: RESOURCE_STATE InitialState, IBuffer** ppBuffer) override final; + /// Implementation of IRenderDeviceVk::CreateBLASFromVulkanResource(). + virtual void DILIGENT_CALL_TYPE CreateBLASFromVulkanResource(VkAccelerationStructureKHR vkBLAS, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + IBottomLevelAS** ppBLAS) override final; + + /// Implementation of IRenderDeviceVk::CreateTLASFromVulkanResource(). + virtual void DILIGENT_CALL_TYPE CreateTLASFromVulkanResource(VkAccelerationStructureKHR vkTLAS, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ITopLevelAS** ppTLAS) override final; + /// Implementation of IRenderDevice::IdleGPU() in Vulkan backend. virtual void DILIGENT_CALL_TYPE IdleGPU() override final; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp index ab43ab80..6adc1677 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp @@ -34,16 +34,17 @@ #include "RenderDeviceVkImpl.hpp" #include "ShaderBindingTableVk.h" #include "ShaderBindingTableBase.hpp" +#include "TopLevelASVkImpl.hpp" #include "PipelineStateVkImpl.hpp" #include "VulkanUtilities/VulkanObjectWrappers.hpp" namespace Diligent { -class ShaderBindingTableVkImpl final : public ShaderBindingTableBase<IShaderBindingTableVk, PipelineStateVkImpl, RenderDeviceVkImpl> +class ShaderBindingTableVkImpl final : public ShaderBindingTableBase<IShaderBindingTableVk, PipelineStateVkImpl, TopLevelASVkImpl, RenderDeviceVkImpl> { public: - using TShaderBindingTableBase = ShaderBindingTableBase<IShaderBindingTableVk, PipelineStateVkImpl, RenderDeviceVkImpl>; + using TShaderBindingTableBase = ShaderBindingTableBase<IShaderBindingTableVk, PipelineStateVkImpl, TopLevelASVkImpl, RenderDeviceVkImpl>; ShaderBindingTableVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, @@ -51,9 +52,6 @@ public: bool bIsDeviceInternal = false); ~ShaderBindingTableVkImpl(); - virtual void DILIGENT_CALL_TYPE ResetHitGroups(Uint32 HitShadersPerInstance) override; - virtual void DILIGENT_CALL_TYPE BindAll(const BindAllAttribs& Attribs) override; - IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderBindingTableVk, TShaderBindingTableBase); }; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp index 44a377fd..97e3dead 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp @@ -396,6 +396,8 @@ public: bool IsUsingSeparateSamplers() const { return m_IsUsingSeparateSamplers; } + bool IsCompatibleWith(const ShaderResourceLayoutVk& ResLayout) const; + private: Uint32 GetResourceOffset(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const { diff --git a/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp index b55223df..a318085e 100644 --- a/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp @@ -47,8 +47,12 @@ public: TopLevelASVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, - const TopLevelASDesc& Desc, - bool bIsDeviceInternal = false); + const TopLevelASDesc& Desc); + TopLevelASVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pRenderDeviceVk, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + VkAccelerationStructureKHR vkTLAS); ~TopLevelASVkImpl(); IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelASVk, TTopLevelASBase); diff --git a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h index dfded94f..0d566e70 100644 --- a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h @@ -112,6 +112,44 @@ DILIGENT_BEGIN_INTERFACE(IRenderDeviceVk, IRenderDevice) const BufferDesc REF BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer) PURE; + + /// Creates a bottom-level AS object from native Vulkan resource + + /// \param [in] vkBLAS - Vulkan acceleration structure handle. + /// \param [in] Desc - Bottom-level AS description. + /// \param [in] InitialState - Initial BLAS state. Can be RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_BUILD_AS_READ, RESOURCE_STATE_BUILD_AS_WRITE. + /// See Diligent::RESOURCE_STATE. + /// \param [out] ppBLAS - Address of the memory location where the pointer to the + /// bottom-level AS interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + /// \note Created bottom-level AS object does not take ownership of the Vulkan acceleration structure and will not + /// destroy it once released. The application must not destroy Vulkan acceleration structure while it is + /// in use by the engine. + VIRTUAL void METHOD(CreateBLASFromVulkanResource)(THIS_ + VkAccelerationStructureKHR vkBLAS, + const BottomLevelASDesc REF Desc, + RESOURCE_STATE InitialState, + IBottomLevelAS** ppBLAS) PURE; + + /// Creates a top-level AS object from native Vulkan resource + + /// \param [in] vkTLAS - Vulkan acceleration structure handle. + /// \param [in] Desc - Bottom-level AS description. + /// \param [in] InitialState - Initial TLAS state. Can be RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_BUILD_AS_READ, RESOURCE_STATE_BUILD_AS_WRITE, RESOURCE_STATE_RAY_TRACING. + /// See Diligent::RESOURCE_STATE. + /// \param [out] ppTLAS - Address of the memory location where the pointer to the + /// top-level AS interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + /// \note Created top-level AS object does not take ownership of the Vulkan acceleration structure and will not + /// destroy it once released. The application must not destroy Vulkan acceleration structure while it is + /// in use by the engine. + VIRTUAL void METHOD(CreateTLASFromVulkanResource)(THIS_ + VkAccelerationStructureKHR vkTLAS, + const TopLevelASDesc REF Desc, + RESOURCE_STATE InitialState, + ITopLevelAS** ppTLAS) PURE; }; DILIGENT_END_INTERFACE @@ -129,6 +167,8 @@ DILIGENT_END_INTERFACE # define IRenderDeviceVk_IsFenceSignaled(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, IsFenceSignaled, This, __VA_ARGS__) # define IRenderDeviceVk_CreateTextureFromVulkanImage(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateTextureFromVulkanImage, This, __VA_ARGS__) # define IRenderDeviceVk_CreateBufferFromVulkanResource(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateBufferFromVulkanResource, This, __VA_ARGS__) +# define IRenderDeviceVk_CreateBLASFromVulkanResource(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateBLASFromVulkanResource, This, __VA_ARGS__) +# define IRenderDeviceVk_CreateTLASFromVulkanResource(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateTLASFromVulkanResource, This, __VA_ARGS__) // clang-format on diff --git a/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp index 092da523..4e23a13a 100644 --- a/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp @@ -34,9 +34,8 @@ namespace Diligent BottomLevelASVkImpl::BottomLevelASVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, - const BottomLevelASDesc& Desc, - bool bIsDeviceInternal) : - TBottomLevelASBase{pRefCounters, pRenderDeviceVk, Desc, bIsDeviceInternal} + const BottomLevelASDesc& Desc) : + TBottomLevelASBase{pRefCounters, pRenderDeviceVk, Desc} { const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice(); @@ -152,6 +151,18 @@ BottomLevelASVkImpl::BottomLevelASVkImpl(IReferenceCounters* pRefCounters, SetState(RESOURCE_STATE_BUILD_AS_READ); } +BottomLevelASVkImpl::BottomLevelASVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pRenderDeviceVk, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + VkAccelerationStructureKHR vkBLAS) : + TBottomLevelASBase{pRefCounters, pRenderDeviceVk, Desc}, + m_VulkanBLAS{vkBLAS} +{ + SetState(InitialState); + m_DeviceAddress = pRenderDeviceVk->GetLogicalDevice().GetAccelerationStructureDeviceAddress(m_VulkanBLAS); +} + BottomLevelASVkImpl::~BottomLevelASVkImpl() { // Vk object can only be destroyed when it is no longer used by the GPU diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index ce9c639c..1b8b3e83 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -2815,21 +2815,23 @@ void DeviceContextVkImpl::BuildBLAS(const BuildBLASAttribs& Attribs) { Geometries.resize(Attribs.TriangleDataCount); Offsets.resize(Attribs.TriangleDataCount); + pBLASVk->SetActualGeometryCount(Attribs.TriangleDataCount); for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i) { const auto& SrcTris = Attribs.pTriangleData[i]; - Uint32 GeoIdx = pBLASVk->GetGeometryIndex(SrcTris.GeometryName); + Uint32 Idx = i; + Uint32 GeoIdx = pBLASVk->UpdateGeometryIndex(SrcTris.GeometryName, Idx, Attribs.Update); - if (GeoIdx >= Geometries.size()) + if (GeoIdx == INVALID_INDEX || Idx == INVALID_INDEX) { UNEXPECTED("Failed to find geometry by name"); continue; } - auto& vkGeo = Geometries[GeoIdx]; + auto& vkGeo = Geometries[Idx]; auto& vkTris = vkGeo.geometry.triangles; - auto& off = Offsets[GeoIdx]; + auto& off = Offsets[Idx]; const auto& TriDesc = BLASDesc.pTriangles[GeoIdx]; vkGeo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; @@ -2886,21 +2888,23 @@ void DeviceContextVkImpl::BuildBLAS(const BuildBLASAttribs& Attribs) { Geometries.resize(Attribs.BoxDataCount); Offsets.resize(Attribs.BoxDataCount); + pBLASVk->SetActualGeometryCount(Attribs.BoxDataCount); for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i) { const auto& SrcBoxes = Attribs.pBoxData[i]; - Uint32 GeoIdx = pBLASVk->GetGeometryIndex(SrcBoxes.GeometryName); + Uint32 Idx = i; + Uint32 GeoIdx = pBLASVk->UpdateGeometryIndex(SrcBoxes.GeometryName, Idx, Attribs.Update); - if (GeoIdx >= Geometries.size()) + if (GeoIdx == INVALID_INDEX || Idx == INVALID_INDEX) { UNEXPECTED("Failed to find geometry by name"); continue; } - auto& vkGeo = Geometries[GeoIdx]; + auto& vkGeo = Geometries[Idx]; auto& vkAABBs = vkGeo.geometry.aabbs; - auto& off = Offsets[GeoIdx]; + auto& off = Offsets[Idx]; vkGeo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; vkGeo.pNext = nullptr; @@ -2928,8 +2932,8 @@ void DeviceContextVkImpl::BuildBLAS(const BuildBLASAttribs& Attribs) Info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; Info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; // type must be compatible with create info Info.flags = BuildASFlagsToVkBuildAccelerationStructureFlags(BLASDesc.Flags); // flags must be compatible with create info - Info.update = VK_FALSE; - Info.srcAccelerationStructure = VK_NULL_HANDLE; + Info.update = Attribs.Update; + Info.srcAccelerationStructure = Attribs.Update ? pBLASVk->GetVkBLAS() : VK_NULL_HANDLE; Info.dstAccelerationStructure = pBLASVk->GetVkBLAS(); Info.geometryArrayOfPointers = VK_FALSE; Info.geometryCount = static_cast<uint32_t>(Geometries.size()); @@ -2963,7 +2967,16 @@ void DeviceContextVkImpl::BuildTLAS(const BuildTLASAttribs& Attribs) TransitionOrVerifyTLASState(*pTLASVk, Attribs.TLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, 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); + if (Attribs.Update) + { + if (!pTLASVk->UpdateInstances(Attribs.pInstances, Attribs.InstanceCount, Attribs.BaseContributionToHitGroupIndex, Attribs.HitShadersPerInstance, Attribs.BindingMode)) + return; + } + else + { + if (!pTLASVk->SetInstanceData(Attribs.pInstances, Attribs.InstanceCount, Attribs.BaseContributionToHitGroupIndex, Attribs.HitShadersPerInstance, Attribs.BindingMode)) + return; + } // copy instance data into instance buffer { @@ -2973,14 +2986,22 @@ void DeviceContextVkImpl::BuildTLAS(const BuildTLASAttribs& Attribs) for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) { const auto& Inst = Attribs.pInstances[i]; - auto& vkASInst = static_cast<VkAccelerationStructureInstanceKHR*>(TmpSpace.CPUAddress)[i]; - auto* const pBLASVk = ValidatedCast<BottomLevelASVkImpl>(Inst.pBLAS); + const auto InstDesc = pTLASVk->GetInstanceDesc(Inst.InstanceName); + + if (InstDesc.InstanceIndex >= Attribs.InstanceCount) + { + UNEXPECTED("Failed to find instance by name"); + return; + } + + auto& vkASInst = static_cast<VkAccelerationStructureInstanceKHR*>(TmpSpace.CPUAddress)[InstDesc.InstanceIndex]; + auto* pBLASVk = ValidatedCast<BottomLevelASVkImpl>(Inst.pBLAS); static_assert(sizeof(vkASInst.transform) == sizeof(Inst.Transform), "size mismatch"); std::memcpy(&vkASInst.transform, Inst.Transform.data, sizeof(vkASInst.transform)); vkASInst.instanceCustomIndex = Inst.CustomId; - vkASInst.instanceShaderBindingTableRecordOffset = pTLASVk->GetInstanceDesc(Inst.InstanceName).ContributionToHitGroupIndex; + vkASInst.instanceShaderBindingTableRecordOffset = InstDesc.ContributionToHitGroupIndex; vkASInst.mask = Inst.Mask; vkASInst.flags = InstanceFlagsToVkGeometryInstanceFlags(Inst.Flags); vkASInst.accelerationStructureReference = pBLASVk->GetVkDeviceAddress(); @@ -3014,8 +3035,8 @@ void DeviceContextVkImpl::BuildTLAS(const BuildTLASAttribs& Attribs) vkASBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; vkASBuildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; // type must be compatible with create info vkASBuildInfo.flags = BuildASFlagsToVkBuildAccelerationStructureFlags(TLASDesc.Flags); // flags must be compatible with create info - vkASBuildInfo.update = VK_FALSE; - vkASBuildInfo.srcAccelerationStructure = VK_NULL_HANDLE; + vkASBuildInfo.update = Attribs.Update; + vkASBuildInfo.srcAccelerationStructure = Attribs.Update ? pTLASVk->GetVkTLAS() : VK_NULL_HANDLE; vkASBuildInfo.dstAccelerationStructure = pTLASVk->GetVkTLAS(); vkASBuildInfo.geometryArrayOfPointers = VK_FALSE; vkASBuildInfo.geometryCount = 1; @@ -3036,7 +3057,8 @@ void DeviceContextVkImpl::CopyBLAS(const CopyBLASAttribs& Attribs) // Dst BLAS description has specified CompactedSize, but doesn't have specified pTriangles and pBoxes. // We should copy geometries because it required for SBT to map geometry name to hit group. - pDstVk->CopyDescription(*pSrcVk); + pDstVk->CopyGeometryDescription(*pSrcVk); + pDstVk->SetActualGeometryCount(pSrcVk->GetActualGeometryCount()); VkCopyAccelerationStructureInfoKHR Info = {}; diff --git a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp index 189b1073..44cf52e3 100644 --- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp @@ -137,8 +137,12 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E try { + Uint32 Version = VK_API_VERSION_1_0; + if (EngineCI.Features.RayTracing != DEVICE_FEATURE_STATE_DISABLED) + Version = VK_API_VERSION_1_2; + auto Instance = VulkanUtilities::VulkanInstance::Create( - VK_API_VERSION_1_2, // AZ TODO: use 1.2 only for ray tracing, wave ops extensions + Version, EngineCI.EnableValidation, EngineCI.GlobalExtensionCount, EngineCI.ppGlobalExtensionNames, diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 6bfd4eeb..cfde6479 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -851,7 +851,7 @@ bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const return false; auto IsSamePipelineLayout = m_PipelineLayout.IsSameAs(pPSOVk->m_PipelineLayout); -#if 0 //def DILIGENT_DEBUG // AZ TODO +#ifdef DILIGENT_DEBUG { bool IsCompatibleShaders = true; if (GetNumShaderStages() != pPSOVk->GetNumShaderStages()) @@ -867,8 +867,8 @@ bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const break; } - const auto& Res0 = GetShaderResLayout(s).GetResources(); - const auto& Res1 = pPSOVk->GetShaderResLayout(s).GetResources(); + const auto& Res0 = GetShaderResLayout(s); + const auto& Res1 = pPSOVk->GetShaderResLayout(s); if (!Res0.IsCompatibleWith(Res1)) { IsCompatibleShaders = false; diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index addf3440..620d29e9 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -754,6 +754,22 @@ void RenderDeviceVkImpl::CreateFramebuffer(const FramebufferDesc& Desc, IFramebu }); } +void RenderDeviceVkImpl::CreateBLASFromVulkanResource(VkAccelerationStructureKHR vkBLAS, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + IBottomLevelAS** ppBLAS) +{ + CreateDeviceObject( + "BottomLevelAS", Desc, ppBLAS, + [&]() // + { + BottomLevelASVkImpl* pBottomLevelASVk(NEW_RC_OBJ(m_BLASAllocator, "BottomLevelASVkImpl instance", BottomLevelASVkImpl)(this, Desc, InitialState, vkBLAS)); + pBottomLevelASVk->QueryInterface(IID_BottomLevelAS, reinterpret_cast<IObject**>(ppBLAS)); + OnCreateDeviceObject(pBottomLevelASVk); + } // + ); +} + void RenderDeviceVkImpl::CreateBLAS(const BottomLevelASDesc& Desc, IBottomLevelAS** ppBLAS) { @@ -766,6 +782,22 @@ void RenderDeviceVkImpl::CreateBLAS(const BottomLevelASDesc& Desc, }); } +void RenderDeviceVkImpl::CreateTLASFromVulkanResource(VkAccelerationStructureKHR vkTLAS, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ITopLevelAS** ppTLAS) +{ + CreateDeviceObject( + "TopLevelAS", Desc, ppTLAS, + [&]() // + { + TopLevelASVkImpl* pTopLevelASVk(NEW_RC_OBJ(m_BLASAllocator, "TopLevelASVkImpl instance", TopLevelASVkImpl)(this, Desc, InitialState, vkTLAS)); + pTopLevelASVk->QueryInterface(IID_TopLevelAS, reinterpret_cast<IObject**>(ppTLAS)); + OnCreateDeviceObject(pTopLevelASVk); + } // + ); +} + void RenderDeviceVkImpl::CreateTLAS(const TopLevelASDesc& Desc, ITopLevelAS** ppTLAS) { diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp index c0228146..194d15f4 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp @@ -45,16 +45,4 @@ ShaderBindingTableVkImpl::~ShaderBindingTableVkImpl() { } -void ShaderBindingTableVkImpl::ResetHitGroups(Uint32 HitShadersPerInstance) -{ - // AZ TODO - - m_Changed = true; -} - -void ShaderBindingTableVkImpl::BindAll(const BindAllAttribs& Attribs) -{ - // AZ TODO -} - } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp index 2e1039ba..26516695 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp @@ -166,9 +166,10 @@ 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 (!pBufferVk->CheckState(RequiredState)) + if (!IsInRequiredState) { LOG_ERROR_MESSAGE("State of buffer '", pBufferVk->GetDesc().Name, "' is incorrect. Required state: ", GetResourceStateString(RequiredState), ". Actual state: ", @@ -180,7 +181,10 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) } else { - pCtxVkImpl->TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + if (!IsInRequiredState) + { + pCtxVkImpl->TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + } VERIFY_EXPR(pBufferVk->CheckAccessFlags(VK_ACCESS_UNIFORM_READ_BIT)); } } @@ -207,10 +211,11 @@ 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 (!pBufferVk->CheckState(RequiredState)) + if (!IsInRequiredState) { LOG_ERROR_MESSAGE("State of buffer '", pBufferVk->GetDesc().Name, "' is incorrect. Required state: ", GetResourceStateString(RequiredState), ". Actual state: ", @@ -222,7 +227,12 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) } else { - pCtxVkImpl->TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + // 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); + } VERIFY_EXPR(pBufferVk->CheckAccessFlags(RequiredAccessFlags)); } } @@ -265,10 +275,11 @@ 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 (!pTextureVk->CheckState(RequiredState)) + if (!IsInRequiredState) { LOG_ERROR_MESSAGE("State of texture '", pTextureVk->GetDesc().Name, "' is incorrect. Required state: ", GetResourceStateString(RequiredState), ". Actual state: ", @@ -280,7 +291,12 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) } else { - pCtxVkImpl->TransitionTextureState(*pTextureVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + // 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); + } } } } @@ -311,10 +327,11 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) auto* pTLASVk = Res.pObject.RawPtr<TopLevelASVkImpl>(); if (pTLASVk != nullptr && pTLASVk->IsInKnownState()) { - constexpr RESOURCE_STATE RequiredState = RESOURCE_STATE_RAY_TRACING; + constexpr RESOURCE_STATE RequiredState = RESOURCE_STATE_RAY_TRACING; + const bool IsInRequiredState = pTLASVk->CheckState(RequiredState); if (VerifyOnly) { - if (!pTLASVk->CheckState(RequiredState)) + if (!IsInRequiredState) { LOG_ERROR_MESSAGE("State of TLAS '", pTLASVk->GetDesc().Name, "' is incorrect. Required state: ", GetResourceStateString(RequiredState), ". Actual state: ", @@ -323,15 +340,18 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state " "with IDeviceContext::TransitionResourceStates()."); } - -#ifdef DILIGENT_DEVELOPMENT - pTLASVk->ValidateContent(); -#endif } else { - pCtxVkImpl->TransitionTLASState(*pTLASVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + if (!IsInRequiredState) + { + pCtxVkImpl->TransitionTLASState(*pTLASVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + } } + +#ifdef DILIGENT_DEVELOPMENT + pTLASVk->ValidateContent(); +#endif } } break; diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index ba8d567a..f45749e2 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -374,27 +374,26 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages& std::string ShadersStr; while (Stages != SHADER_TYPE_UNKNOWN) { - const auto ShaderType = Stages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(Stages) - 1)); - const char* ShaderName = nullptr; + const auto ShaderType = Stages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(Stages) - 1)); + String ShaderName; - // AZ TODO - /*for (const auto& StageInfo : ShaderStages) + for (const auto& StageInfo : ShaderStages) { if ((Stages & StageInfo.Type) != 0) { - ShaderName = StageInfo.pShader->GetDesc().Name; + ShaderName = GetShaderGroupName(StageInfo.Shaders); break; } - }*/ + } if (!ShadersStr.empty()) ShadersStr.append(", "); ShadersStr.append(GetShaderTypeLiteralName(ShaderType)); ShadersStr.append(" ("); - if (ShaderName) + if (ShaderName.size()) { ShadersStr.push_back('\''); - ShadersStr.append(ShaderName ? ShaderName : "<Not enabled in PSO>"); + ShadersStr.append(ShaderName); ShadersStr.push_back('\''); } else @@ -829,10 +828,10 @@ void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject* if (pBufferVk->GetDesc().uiSizeInBytes < BufferStaticSize) { - std::stringstream ss; - ss << "The size of buffer '" << pBufferVk->GetDesc().Name << "' (" << pBufferVk->GetDesc().uiSizeInBytes - << ") is not large enough for what the shader expects (" << BufferStaticSize << ")"; - LOG_ERROR_MESSAGE(ss.str()); + // It is OK if enabled robustBufferAccess feature, otherwise access outside of buffer range may lead to crash or undefined behavior. + LOG_WARNING_MESSAGE("Error binding uniform buffer '", pBufferVk->GetDesc().Name, "' to shader variable '", + Name, "' in shader '", ParentResLayout.GetShaderName(), "': buffer size in the shader (", + BufferStaticSize, ") is incompatible with the actual buffer size (", pBufferVk->GetDesc().uiSizeInBytes, ")."); } #endif @@ -888,11 +887,22 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* Name, "' in shader '", ParentResLayout.GetShaderName(), "': structured buffer view is expected."); } - if (ViewDesc.ByteWidth < BufferStaticSize || (ViewDesc.ByteWidth - BufferStaticSize) % BufferStride != 0) + if (BufferStride == 0 && ViewDesc.ByteWidth < BufferStaticSize) { - LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", - Name, "' in shader '", ParentResLayout.GetShaderName(), "': static buffer size in the shader (", - BufferStaticSize, ") and array element stride (", BufferStride, ") are incompatible with the actual buffer size (", ViewDesc.ByteWidth, ")."); + // It is OK if enabled robustBufferAccess feature, otherwise access outside of buffer range may lead to crash or undefined behavior. + LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + Name, "' in shader '", ParentResLayout.GetShaderName(), "': buffer size in the shader (", + BufferStaticSize, ") is incompatible with the actual buffer view size (", ViewDesc.ByteWidth, ")."); + } + + if (BufferStride > 0 && (ViewDesc.ByteWidth < BufferStaticSize || (ViewDesc.ByteWidth - BufferStaticSize) % BufferStride != 0)) + { + // For buffers with dynamic arrays we know only static part size and array element stride. + // Element stride in shader may be differ than in code. Here we check that buffer size is exactly match to the array with N elements. + LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + Name, "' in shader '", ParentResLayout.GetShaderName(), "': static buffer size in the shader (", + BufferStaticSize, ") and array element stride (", BufferStride, ") are incompatible with the actual buffer view size (", ViewDesc.ByteWidth, "),", + " this may be result of array element size mismatch."); } } } @@ -1117,7 +1127,7 @@ void ShaderResourceLayoutVk::VkResource::CacheAccelerationStructure(IDeviceObjec VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration Structure resource is expected"); RefCntAutoPtr<TopLevelASVkImpl> pTLASVk{pTLAS, IID_TopLevelASVk}; #ifdef DILIGENT_DEVELOPMENT - // AZ TODO + VerifyTLASResourceBinding(*this, GetVariableType(), ArrayInd, pTLASVk.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); #endif if (UpdateCachedResource(DstRes, std::move(pTLASVk), [](const TopLevelASVkImpl*, const TopLevelASVkImpl*) {})) { @@ -1536,4 +1546,28 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& } } +bool ShaderResourceLayoutVk::IsCompatibleWith(const ShaderResourceLayoutVk& ResLayout) const +{ + if (m_NumResources != ResLayout.m_NumResources) + return false; + + bool IsCompatible = true; + for (Uint32 i = 0, Cnt = GetTotalResourceCount(); i < Cnt; ++i) + { + const auto& lhs = this->GetResource(i); + const auto& rhs = ResLayout.GetResource(i); + + // clang-format off + if (lhs.ArraySize != rhs.ArraySize || + lhs.Type != rhs.Type || + lhs.SamplerInd != rhs.SamplerInd) + // clang-format on + { + IsCompatible = false; + } + } + + return IsCompatible; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp index fbef736c..bfde3aa6 100644 --- a/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp @@ -34,9 +34,8 @@ namespace Diligent TopLevelASVkImpl::TopLevelASVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, - const TopLevelASDesc& Desc, - bool bIsDeviceInternal) : - TTopLevelASBase{pRefCounters, pRenderDeviceVk, Desc, bIsDeviceInternal} + const TopLevelASDesc& Desc) : + TTopLevelASBase{pRefCounters, pRenderDeviceVk, Desc} { const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice(); @@ -104,6 +103,17 @@ TopLevelASVkImpl::TopLevelASVkImpl(IReferenceCounters* pRefCounters, SetState(RESOURCE_STATE_BUILD_AS_READ); } +TopLevelASVkImpl::TopLevelASVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pRenderDeviceVk, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + VkAccelerationStructureKHR vkTLAS) : + TTopLevelASBase{pRefCounters, pRenderDeviceVk, Desc}, + m_VulkanTLAS{vkTLAS} +{ + SetState(InitialState); +} + TopLevelASVkImpl::~TopLevelASVkImpl() { // Vk object can only be destroyed when it is no longer used by the GPU diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index a80d7f73..fd81dcfb 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -189,7 +189,6 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice, // Emulate KHR extension if (m_ExtFeatures.RayTracingNV) { - //m_ExtFeatures.RayTracing.rayTracingPrimitiveCulling = true; // AZ TODO m_ExtFeatures.RayTracing.rayTracing = VK_TRUE; m_ExtProperties.RayTracing.shaderGroupHandleSize = RayTracingNV.shaderGroupHandleSize; |
