summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngine
diff options
context:
space:
mode:
authorazhirnov <zh1dron@gmail.com>2020-11-07 19:34:49 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-11-10 03:43:28 +0000
commit0f35896a60c4de02ccfc91ace18bcef4450fa4d9 (patch)
tree86a772a36c6c2258949231b756970a621b69f82b /Graphics/GraphicsEngine
parentCorrected ray rtacing vertex format handling in D3D12 (diff)
downloadDiligentCore-0f35896a60c4de02ccfc91ace18bcef4450fa4d9.tar.gz
DiligentCore-0f35896a60c4de02ccfc91ace18bcef4450fa4d9.zip
Added ability to update AS.
Diffstat (limited to 'Graphics/GraphicsEngine')
-rw-r--r--Graphics/GraphicsEngine/include/BottomLevelASBase.hpp124
-rw-r--r--Graphics/GraphicsEngine/include/DeviceContextBase.hpp25
-rw-r--r--Graphics/GraphicsEngine/include/PipelineStateBase.hpp13
-rw-r--r--Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp312
-rw-r--r--Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp52
-rw-r--r--Graphics/GraphicsEngine/include/TopLevelASBase.hpp257
-rw-r--r--Graphics/GraphicsEngine/interface/BottomLevelAS.h61
-rw-r--r--Graphics/GraphicsEngine/interface/DeviceContext.h92
-rw-r--r--Graphics/GraphicsEngine/interface/PipelineState.h9
-rw-r--r--Graphics/GraphicsEngine/interface/ShaderBindingTable.h169
-rw-r--r--Graphics/GraphicsEngine/interface/TopLevelAS.h61
-rw-r--r--Graphics/GraphicsEngine/src/BottomLevelASBase.cpp46
-rw-r--r--Graphics/GraphicsEngine/src/DeviceContextBase.cpp213
13 files changed, 1041 insertions, 393 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.");