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