summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngine
diff options
context:
space:
mode:
authorazhirnov <zh1dron@gmail.com>2020-10-04 20:23:28 +0000
committerazhirnov <zh1dron@gmail.com>2020-10-04 20:32:25 +0000
commit7838459ef71fe5f0979f30df8348a6981363d6c8 (patch)
tree0fea27225f76476cd5e19f0b11e4c574040f7bfb /Graphics/GraphicsEngine
parentAdded dummy implementation for D3D11, D3D12, OpenGL (diff)
downloadDiligentCore-7838459ef71fe5f0979f30df8348a6981363d6c8.tar.gz
DiligentCore-7838459ef71fe5f0979f30df8348a6981363d6c8.zip
Added Vulkan implementation
Diffstat (limited to 'Graphics/GraphicsEngine')
-rw-r--r--Graphics/GraphicsEngine/include/BottomLevelASBase.hpp194
-rw-r--r--Graphics/GraphicsEngine/include/DeviceContextBase.hpp371
-rw-r--r--Graphics/GraphicsEngine/include/RenderDeviceBase.hpp17
-rw-r--r--Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp96
-rw-r--r--Graphics/GraphicsEngine/include/TopLevelASBase.hpp147
5 files changed, 823 insertions, 2 deletions
diff --git a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp
new file mode 100644
index 00000000..e0fcde4f
--- /dev/null
+++ b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Implementation of the Diligent::BottomLevelASBase template class
+
+#include "BottomLevelAS.h"
+#include "DeviceObjectBase.hpp"
+#include "RenderDeviceBase.hpp"
+#include "StringPool.hpp"
+#include "StringView.hpp"
+#include <map>
+
+namespace Diligent
+{
+
+/// Template class implementing base functionality for a bottom-level acceleration structure object.
+
+/// \tparam BaseInterface - base interface that this class will inheret
+/// (Diligent::IBottomLevelASD3D12 or Diligent::IBottomLevelASVk).
+/// \tparam RenderDeviceImplType - type of the render device implementation
+/// (Diligent::RenderDeviceD3D12Impl or Diligent::RenderDeviceVkImpl)
+template <class BaseInterface, class RenderDeviceImplType>
+class BottomLevelASBase : public DeviceObjectBase<BaseInterface, RenderDeviceImplType, BottomLevelASDesc>
+{
+public:
+ using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, BottomLevelASDesc>;
+
+ /// \param pRefCounters - reference counters object that controls the lifetime of this BLAS.
+ /// \param pDevice - pointer to the device.
+ /// \param Desc - BLAS description.
+ /// \param bIsDeviceInternal - flag indicating if the BLAS is an internal device object and
+ /// must not keep a strong reference to the device.
+ BottomLevelASBase(IReferenceCounters* pRefCounters, RenderDeviceImplType* pDevice, const BottomLevelASDesc& Desc, bool bIsDeviceInternal = false) :
+ TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}
+ {
+ ValidateBottomLevelASDesc(Desc);
+
+ // Memory must be released even if exception was thrown.
+ struct MemOwner
+ {
+ void* ptr = nullptr;
+
+ ~MemOwner()
+ {
+ if (ptr != nullptr)
+ GetRawAllocator().Free(ptr);
+ }
+ } memOwner;
+
+ if (Desc.pTriangles != nullptr)
+ {
+ size_t StringPoolSize = 0;
+ for (Uint32 i = 0; i < Desc.TriangleCount; ++i)
+ {
+ if (Desc.pTriangles[i].GeometryName == nullptr)
+ LOG_ERROR_AND_THROW("Geometry name can not be null!");
+
+ StringPoolSize += strlen(Desc.pTriangles[i].GeometryName) + 1;
+ }
+
+ m_StringPool.Reserve(StringPoolSize, GetRawAllocator());
+
+ auto* pTriangles = ALLOCATE(GetRawAllocator(), "Memory for BLASTriangleDesc array", BLASTriangleDesc, Desc.TriangleCount);
+ memOwner.ptr = pTriangles;
+
+ std::memcpy(pTriangles, Desc.pTriangles, sizeof(*Desc.pTriangles) * Desc.TriangleCount);
+ this->m_Desc.pTriangles = pTriangles;
+ this->m_Desc.pBoxes = nullptr;
+
+ // copy strings
+ for (Uint32 i = 0; i < Desc.TriangleCount; ++i)
+ {
+ pTriangles[i].GeometryName = m_StringPool.CopyString(pTriangles[i].GeometryName);
+ bool IsUniqueName = m_NameToIndex.insert({StringView{pTriangles[i].GeometryName}, i}).second;
+ if (!IsUniqueName)
+ LOG_ERROR_AND_THROW("Geometry name must be unique!");
+ }
+ }
+ else if (Desc.pBoxes != nullptr)
+ {
+ size_t StringPoolSize = 0;
+ for (Uint32 i = 0; i < Desc.TriangleCount; ++i)
+ {
+ if (Desc.pBoxes[i].GeometryName == nullptr)
+ LOG_ERROR_AND_THROW("Geometry name can not be null!");
+
+ StringPoolSize += strlen(Desc.pBoxes[i].GeometryName) + 1;
+ }
+
+ m_StringPool.Reserve(StringPoolSize, GetRawAllocator());
+
+ auto* pBoxes = ALLOCATE(GetRawAllocator(), "Memory for BLASBoundingBoxDesc array", BLASBoundingBoxDesc, Desc.BoxCount);
+ memOwner.ptr = pBoxes;
+
+ std::memcpy(pBoxes, Desc.pBoxes, sizeof(*Desc.pBoxes) * Desc.BoxCount);
+ this->m_Desc.pBoxes = pBoxes;
+ this->m_Desc.pTriangles = nullptr;
+
+ // copy strings
+ for (Uint32 i = 0; i < Desc.TriangleCount; ++i)
+ {
+ pBoxes[i].GeometryName = m_StringPool.CopyString(pBoxes[i].GeometryName);
+ bool IsUniqueName = m_NameToIndex.insert({StringView{pBoxes[i].GeometryName}, i}).second;
+ if (!IsUniqueName)
+ LOG_ERROR_AND_THROW("Geometry name must be unique!");
+ }
+ }
+
+ // Constructor completed successfully and memory will be released in destructor.
+ memOwner.ptr = nullptr;
+ }
+
+ ~BottomLevelASBase()
+ {
+ if (this->m_Desc.pTriangles != nullptr)
+ {
+ GetRawAllocator().Free(const_cast<BLASTriangleDesc*>(this->m_Desc.pTriangles));
+ }
+ if (this->m_Desc.pBoxes != nullptr)
+ {
+ GetRawAllocator().Free(const_cast<BLASBoundingBoxDesc*>(this->m_Desc.pBoxes));
+ }
+ }
+
+ virtual Uint32 DILIGENT_CALL_TYPE GetGeometryIndex(const char* Name) const override
+ {
+ VERIFY_EXPR(Name != nullptr && Name[0] != '\0');
+
+ auto iter = m_NameToIndex.find(StringView{Name});
+ if (iter != m_NameToIndex.end())
+ return iter->second;
+
+ UNEXPECTED("Can't find geometry with specified name");
+ return ~0u; // AZ TODO
+ }
+
+protected:
+ static void ValidateBottomLevelASDesc(const BottomLevelASDesc& Desc)
+ {
+#define LOG_BLAS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of Bottom-level AS '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
+
+ if (!((Desc.pBoxes != nullptr) ^ (Desc.pTriangles != nullptr)))
+ {
+ LOG_BLAS_ERROR_AND_THROW("Only one of pTriangles and pBoxes must be defined");
+ }
+
+ if (Desc.pBoxes == nullptr && Desc.BoxCount > 0)
+ {
+ LOG_BLAS_ERROR_AND_THROW("pBoxes is null but BoxCount is not 0");
+ }
+
+ if (Desc.pTriangles == nullptr && Desc.TriangleCount > 0)
+ {
+ LOG_BLAS_ERROR_AND_THROW("pTriangles is null but TriangleCount is not 0");
+ }
+
+#undef LOG_BLAS_ERROR_AND_THROW
+ }
+
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BottomLevelAS, TDeviceObjectBase)
+
+protected:
+ std::map<StringView, Uint32> m_NameToIndex;
+ StringPool m_StringPool;
+};
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
index 86cccc7b..57c2ba16 100644
--- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
+++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
@@ -273,6 +273,14 @@ protected:
// clang-format on
#endif
+ bool BuildBLAS(const BLASBuildAttribs& Attribs, int);
+ bool BuildTLAS(const TLASBuildAttribs& Attribs, int);
+ bool CopyBLAS(const CopyBLASAttribs& Attribs, int);
+ bool CopyTLAS(const CopyTLASAttribs& Attribs, int);
+ bool TraceRays(const TraceRaysAttribs& Attribs, int);
+
+ static const Uint32 TLASInstanceDataSize = 64; // bytes
+
/// Strong reference to the device.
RefCntAutoPtr<DeviceImplType> m_pDevice;
@@ -1828,7 +1836,7 @@ void DeviceContextBase<BaseInterface, ImplementationTraits>::
"Failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device");
}
}
- else
+ else if (Barrier.pBuffer)
{
const auto& BuffDesc = Barrier.pBuffer->GetDesc();
DEV_CHECK_ERR(VerifyResourceStates(Barrier.NewState, false), "Invlaid new state specified for buffer '", BuffDesc.Name, "'");
@@ -1836,6 +1844,10 @@ void DeviceContextBase<BaseInterface, ImplementationTraits>::
DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of buffer '", BuffDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier");
DEV_CHECK_ERR(VerifyResourceStates(OldState, false), "Invlaid old state specified for buffer '", BuffDesc.Name, "'");
}
+ else
+ {
+ // AZ TODO: global barrier
+ }
if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS)
{
@@ -1880,4 +1892,361 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>::
#endif // DILIGENT_DEVELOPMENT
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::BuildBLAS(const BLASBuildAttribs& Attribs, int)
+{
+ if (Attribs.pBLAS == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBLAS must not be null");
+ return false;
+ }
+
+ if (Attribs.pScratchBuffer == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pScratchBuffer must not be null");
+ return false;
+ }
+
+ if ((Attribs.pTriangleData != nullptr) ^ (Attribs.pBoxData != nullptr))
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: only one of pTriangles and pBoxes must be defined");
+ return false;
+ }
+
+ if (Attribs.pBoxData == nullptr && Attribs.BoxDataCount > 0)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBoxData is null but BoxDataCount is not 0");
+ return false;
+ }
+
+ if (Attribs.pTriangleData == nullptr && Attribs.TriangleDataCount > 0)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData is null but TriangleDataCount is not 0");
+ return false;
+ }
+
+ for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i)
+ {
+ if (Attribs.pTriangleData[i].pVertexBuffer == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].pVertexBuffer must not be null");
+ return false;
+ }
+
+ if ((Attribs.pTriangleData[i].pVertexBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].pVertexBuffer must be created with BIND_RAY_TRACING flag");
+ return false;
+ }
+
+ if (Attribs.pTriangleData[i].IndexType != VT_UNDEFINED)
+ {
+ if (Attribs.pTriangleData[i].pIndexBuffer == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].pIndexBuffer must not be null");
+ return false;
+ }
+
+ if ((Attribs.pTriangleData[i].pIndexBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].pIndexBuffer must be created with BIND_RAY_TRACING flag");
+ return false;
+ }
+ }
+
+ // AZ TODO: check AllosTransforms flags in create info
+ if (Attribs.pTriangleData[i].pTransformBuffer != nullptr)
+ {
+ if ((Attribs.pTriangleData[i].pTransformBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].pTransformBuffer must be created with BIND_RAY_TRACING flag");
+ return false;
+ }
+ }
+ }
+
+ for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i)
+ {
+ if (Attribs.pBoxData[i].pBoxBuffer == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBoxData[", i, "].pBoxBuffer must not be null");
+ return false;
+ }
+
+ if ((Attribs.pBoxData[i].pBoxBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBoxData[", i, "].pBoxBuffer must be created with BIND_RAY_TRACING flag");
+ return false;
+ }
+ }
+
+ const auto& BLASDesc = Attribs.pBLAS->GetDesc();
+
+ if (Attribs.BoxDataCount > BLASDesc.BoxCount)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: BoxDataCount must be less than or equal to Attribs.pBLAS->GetDesc().BoxCount");
+ return false;
+ }
+
+ if (Attribs.TriangleDataCount > BLASDesc.TriangleCount)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: TriangleDataCount must be less than or equal to Attribs.pBLAS->GetDesc().TriangleCount");
+ return false;
+ }
+
+ const auto& ScratchDesc = Attribs.pScratchBuffer->GetDesc();
+
+ if (Attribs.ScratchBufferOffset > ScratchDesc.uiSizeInBytes)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: ScratchBufferOffset is greater than buffer size");
+ return false;
+ }
+
+ if (ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset > Attribs.pBLAS->GetScratchBufferSizes().Build)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pScratchBuffer size is too small, use pBLAS->GetScratchBufferSizes().Build to get required size for scratch buffer");
+ return false;
+ }
+
+ if ((ScratchDesc.BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must be created with BIND_RAY_TRACING flag");
+ return false;
+ }
+
+ return true;
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::BuildTLAS(const TLASBuildAttribs& Attribs, int)
+{
+ if (Attribs.pTLAS == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pTLAS must not be null");
+ return false;
+ }
+
+ if (Attribs.pScratchBuffer == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must not be null");
+ return false;
+ }
+
+ if (Attribs.pInstances == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances must not be null");
+ return false;
+ }
+
+ if (Attribs.pInstancesBuffer == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceaBuffer must not be null");
+ return false;
+ }
+
+ if (Attribs.HitShadersPerInstance > 0)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: HitShadersPerInstance must be greater than 0");
+ return false;
+ }
+
+ const auto& TLASDesc = Attribs.pTLAS->GetDesc();
+
+ if (Attribs.InstanceCount > TLASDesc.MaxInstanceCount)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: InstanceCount must be less than or equal to Attribs.pTLAS->GetDesc().MaxInstanceCount");
+ return false;
+ }
+
+ const auto& InstDesc = Attribs.pInstancesBuffer->GetDesc();
+ const size_t InstDataSize = Attribs.InstanceCount * TLASInstanceDataSize;
+
+ // calculate instance data size
+ for (Uint32 i = 0; i < Attribs.InstanceCount; ++i)
+ {
+ VERIFY_EXPR((Attribs.pInstances[i].customId & 0x00FFFFFF) == 0);
+ VERIFY_EXPR((Attribs.pInstances[i].contributionToHitGroupIndex & 0x00FFFFFF) == 0);
+
+ if (Attribs.pInstances[i].InstanceName == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances[", i, "].InstanceName must not be null");
+ return false;
+ }
+
+ if (Attribs.pInstances[i].pBLAS == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances[", i, "].pBLAS must not be null");
+ return false;
+ }
+ }
+
+ if (Attribs.InstancesBufferOffset > InstDesc.uiSizeInBytes)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: InstancesBufferOffset is greater than buffer size");
+ return false;
+ }
+
+ if (InstDesc.uiSizeInBytes - Attribs.InstancesBufferOffset > InstDataSize)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceaBuffer size is too small, ...");
+ return false;
+ }
+
+ if ((InstDesc.BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceaBuffer must be created with BIND_RAY_TRACING flag");
+ return false;
+ }
+
+ const auto& ScratchDesc = Attribs.pScratchBuffer->GetDesc();
+
+ if (Attribs.ScratchBufferOffset > ScratchDesc.uiSizeInBytes)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: ScratchBufferOffset is greater than buffer size");
+ return false;
+ }
+
+ if (ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset > Attribs.pTLAS->GetScratchBufferSizes().Build)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer size is too small, use pTLAS->GetScratchBufferSizes().Build to get required size for scratch buffer");
+ return false;
+ }
+
+ if ((ScratchDesc.BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must be created with BIND_RAY_TRACING flag");
+ return false;
+ }
+
+ return true;
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::CopyBLAS(const CopyBLASAttribs& Attribs, int)
+{
+ if (Attribs.pSrc == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: pSrc must not be null");
+ return false;
+ }
+
+ if (Attribs.pDst == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: pDst must not be null");
+ return false;
+ }
+
+ if (Attribs.Mode == COPY_AS_MODE_CLONE)
+ {
+ auto& SrcDesc = Attribs.pSrc->GetDesc();
+ auto& DstDesc = Attribs.pDst->GetDesc();
+
+ if (SrcDesc.TriangleCount != DstDesc.TriangleCount)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different TriangleCount, pDst must have been created with the same parameters as pSrc");
+ return false;
+ }
+
+ if (SrcDesc.BoxCount != DstDesc.BoxCount)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different BoxCount, pDst must have been created with the same parameters as pSrc");
+ return false;
+ }
+
+ if (SrcDesc.Flags != DstDesc.Flags)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different Flags, pDst must have been created with the same parameters as pSrc");
+ return false;
+ }
+
+ for (Uint32 i = 0; i < SrcDesc.TriangleCount; ++i)
+ {
+ auto& SrcTri = SrcDesc.pTriangles[i];
+ auto& DstTri = DstDesc.pTriangles[i];
+
+ if (SrcTri.MaxVertexCount != DstTri.MaxVertexCount ||
+ SrcTri.VertexValueType != DstTri.VertexValueType ||
+ SrcTri.VertexComponentCount != DstTri.VertexComponentCount ||
+ SrcTri.MaxIndexCount != DstTri.MaxIndexCount ||
+ SrcTri.IndexType != DstTri.IndexType ||
+ SrcTri.AllowsTransforms != DstTri.AllowsTransforms)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different triangles description at index: ", i, ", pDst must have been created with the same parameters as pSrc");
+ return false;
+ }
+ }
+
+ for (Uint32 i = 0; i < SrcDesc.BoxCount; ++i)
+ {
+ if (SrcDesc.pBoxes[i].MaxBoxCount != DstDesc.pBoxes[i].MaxBoxCount)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different boxes description at index: ", i, ", pDst must have been created with the same parameters as pSrc");
+ return false;
+ }
+ }
+ return true;
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: unknown Mode");
+ return false;
+ }
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::CopyTLAS(const CopyTLASAttribs& Attribs, int)
+{
+ if (Attribs.pSrc == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pSrc must not be null");
+ return false;
+ }
+
+ if (Attribs.pDst == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pDst must not be null");
+ return false;
+ }
+
+ if (Attribs.Mode == COPY_AS_MODE_CLONE)
+ {
+ auto& SrcDesc = Attribs.pSrc->GetDesc();
+ auto& DstDesc = Attribs.pDst->GetDesc();
+
+ if (SrcDesc.MaxInstanceCount != DstDesc.MaxInstanceCount ||
+ SrcDesc.Flags != DstDesc.Flags)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pDst must have been created with the same parameters as pSrc");
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: unknown Mode");
+ return false;
+ }
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::TraceRays(const TraceRaysAttribs& Attribs, int)
+{
+ if (Attribs.pSBT == nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::TraceRays: pSBT must not be null");
+ return false;
+ }
+
+ if (Attribs.DimensionX == 0)
+ LOG_WARNING_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: DimensionX is zero.");
+
+ if (Attribs.DimensionY == 0)
+ LOG_WARNING_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: DimensionY is zero.");
+
+ if (Attribs.DimensionZ == 0)
+ LOG_WARNING_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: DimensionZ is zero.");
+
+ return true;
+}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp
index f406bf4e..82d5049b 100644
--- a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp
+++ b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp
@@ -226,6 +226,15 @@ public:
/// Size of the framebuffer object (FramebufferD3D12Impl, FramebufferVkImpl, etc.), in bytes
const size_t FramebufferObjSize;
+
+ /// Size of the BLAS object (BottomLevelASD3D12Impl, BottomLevelASVkImpl, etc.), in bytes
+ const size_t BLASObjSize;
+
+ /// Size of the TLAS object (TopLevelASD3D12Impl, TopLevelASVkImpl, etc.), in bytes
+ const size_t TLASObjSize;
+
+ /// Size of the SBT object (ShaderBindingTableD3D12Impl, ShaderBindingtableVkImpl, etc.), in bytes
+ const size_t SBTObjSize;
};
/// \param pRefCounters - reference counters object that controls the lifetime of this render device
@@ -261,7 +270,10 @@ public:
m_FenceAllocator {RawMemAllocator, ObjectSizes.FenceSize, 16 },
m_QueryAllocator {RawMemAllocator, ObjectSizes.QuerySize, 16 },
m_RenderPassAllocator {RawMemAllocator, ObjectSizes.RenderPassObjSize, 16 },
- m_FramebufferAllocator {RawMemAllocator, ObjectSizes.FramebufferObjSize, 16 }
+ m_FramebufferAllocator {RawMemAllocator, ObjectSizes.FramebufferObjSize, 16 },
+ m_BLASAllocator {RawMemAllocator, ObjectSizes.BLASObjSize, 16 },
+ m_TLASAllocator {RawMemAllocator, ObjectSizes.TLASObjSize, 16 },
+ m_SBTAllocator {RawMemAllocator, ObjectSizes.SBTObjSize, 16 }
// clang-format on
{
// Initialize texture format info
@@ -436,6 +448,9 @@ protected:
FixedBlockMemoryAllocator m_QueryAllocator; ///< Allocator for query objects
FixedBlockMemoryAllocator m_RenderPassAllocator; ///< Allocator for render pass objects
FixedBlockMemoryAllocator m_FramebufferAllocator; ///< Allocator for framebuffer objects
+ FixedBlockMemoryAllocator m_BLASAllocator; ///< Allocator for bottom-level acceleration structure objects
+ FixedBlockMemoryAllocator m_TLASAllocator; ///< Allocator for top-level acceleration structure objects
+ FixedBlockMemoryAllocator m_SBTAllocator; ///< Allocator for shader binding table objects
};
diff --git a/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp
new file mode 100644
index 00000000..d615450a
--- /dev/null
+++ b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Implementation of the Diligent::ShaderBindingTableBase template class
+
+#include "ShaderBindingTable.h"
+#include "DeviceObjectBase.hpp"
+#include "RenderDeviceBase.hpp"
+#include "StringPool.hpp"
+#include "StringView.hpp"
+#include <map>
+
+namespace Diligent
+{
+
+/// Template class implementing base functionality for a shader binding table object.
+
+/// \tparam BaseInterface - base interface that this class will inheret
+/// (Diligent::IShaderBindingTableD3D12 or Diligent::IShaderBindingTableVk).
+/// \tparam RenderDeviceImplType - type of the render device implementation
+/// (Diligent::RenderDeviceD3D12Impl or Diligent::RenderDeviceVkImpl)
+template <class BaseInterface, class RenderDeviceImplType>
+class ShaderBindingTableBase : public DeviceObjectBase<BaseInterface, RenderDeviceImplType, ShaderBindingTableDesc>
+{
+public:
+ using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, ShaderBindingTableDesc>;
+
+ /// \param pRefCounters - reference counters object that controls the lifetime of this SBT.
+ /// \param pDevice - pointer to the device.
+ /// \param Desc - SBT description.
+ /// \param bIsDeviceInternal - flag indicating if the BLAS is an internal device object and
+ /// must not keep a strong reference to the device.
+ ShaderBindingTableBase(IReferenceCounters* pRefCounters, RenderDeviceImplType* pDevice, const ShaderBindingTableDesc& Desc, bool bIsDeviceInternal = false) :
+ TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}
+ {
+ ValidateShaderBindingTableDesc(Desc);
+ }
+
+ ~ShaderBindingTableBase()
+ {
+ }
+
+protected:
+ static void ValidateShaderBindingTableDesc(const ShaderBindingTableDesc& Desc)
+ {
+#define LOG_SBT_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of Shader binding table '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
+
+ if (Desc.pPSO == nullptr)
+ {
+ LOG_SBT_ERROR_AND_THROW("PipelineState must not be null");
+ }
+
+ if (Desc.pPSO->GetDesc().PipelineType != PIPELINE_TYPE_RAY_TRACING)
+ {
+ LOG_SBT_ERROR_AND_THROW("PipelineState must be ray tracing pipeline");
+ }
+
+#undef LOG_SBT_ERROR_AND_THROW
+ }
+
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderBindingTable, TDeviceObjectBase)
+
+protected:
+ std::map<StringView, Uint32> m_NameToIndex;
+ StringPool m_StringPool;
+ std::map<StringView, TLASInstanceDesc> m_Instances;
+};
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/TopLevelASBase.hpp b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp
new file mode 100644
index 00000000..143cf54f
--- /dev/null
+++ b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Implementation of the Diligent::TopLevelASBase template class
+
+#include "TopLevelAS.h"
+#include "DeviceObjectBase.hpp"
+#include "RenderDeviceBase.hpp"
+#include "StringPool.hpp"
+#include "StringView.hpp"
+#include <map>
+
+namespace Diligent
+{
+
+/// Template class implementing base functionality for a top-level acceleration structure object.
+
+/// \tparam BaseInterface - base interface that this class will inheret
+/// (Diligent::ITopLevelASD3D12 or Diligent::ITopLevelASVk).
+/// \tparam RenderDeviceImplType - type of the render device implementation
+/// (Diligent::RenderDeviceD3D12Impl or Diligent::RenderDeviceVkImpl)
+template <class BaseInterface, class RenderDeviceImplType>
+class TopLevelASBase : public DeviceObjectBase<BaseInterface, RenderDeviceImplType, TopLevelASDesc>
+{
+public:
+ using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, TopLevelASDesc>;
+
+ /// \param pRefCounters - reference counters object that controls the lifetime of this BLAS.
+ /// \param pDevice - pointer to the device.
+ /// \param Desc - TLAS description.
+ /// \param bIsDeviceInternal - flag indicating if the BLAS is an internal device object and
+ /// must not keep a strong reference to the device.
+ TopLevelASBase(IReferenceCounters* pRefCounters, RenderDeviceImplType* pDevice, const TopLevelASDesc& Desc, bool bIsDeviceInternal = false) :
+ TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}
+ {
+ ValidateTopLevelASDesc(Desc);
+ }
+
+ ~TopLevelASBase()
+ {
+ }
+
+ void SetInstanceData(const TLASBuildInstanceData* pInstances, Uint32 InstanceCount)
+ {
+ m_Instances.clear();
+ m_StringPool.Release();
+
+ size_t StringPoolSize = 0;
+ for (Uint32 i = 0; i < InstanceCount; ++i)
+ {
+ StringPoolSize += strlen(pInstances[i].InstanceName) + 1;
+ }
+
+ m_StringPool.Reserve(StringPoolSize, GetRawAllocator());
+
+ for (Uint32 i = 0; i < InstanceCount; ++i)
+ {
+ auto& inst = pInstances[i];
+ const char* NameCopy = m_StringPool.CopyString(inst.InstanceName);
+ InstanceDesc Desc = {};
+
+ Desc.contributionToHitGroupIndex = inst.contributionToHitGroupIndex;
+ Desc.pBLAS = inst.pBLAS;
+
+ bool IsUniqueName = m_Instances.insert_or_assign(StringView{NameCopy}, Desc).second;
+ if (!IsUniqueName)
+ LOG_ERROR_AND_THROW("Instance name must be unique!");
+ }
+ }
+
+ virtual TLASInstanceDesc DILIGENT_CALL_TYPE GetInstanceDesc(const char* Name) const override
+ {
+ VERIFY_EXPR(Name != nullptr && Name[0] != '\0');
+
+ TLASInstanceDesc Result = {};
+
+ auto iter = m_Instances.find(StringView{Name});
+ if (iter != m_Instances.end())
+ {
+ Result.contributionToHitGroupIndex = iter->second.contributionToHitGroupIndex;
+ Result.pBLAS = iter->second.pBLAS;
+ return Result;
+ }
+
+ UNEXPECTED("Can't find instance with specified name");
+ return Result;
+ }
+
+protected:
+ static void ValidateTopLevelASDesc(const TopLevelASDesc& Desc)
+ {
+#define LOG_TLAS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of Top-level AS '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
+
+ if (Desc.MaxInstanceCount == 0)
+ {
+ LOG_TLAS_ERROR_AND_THROW("MaxInstanceCount must not be zero");
+ }
+
+ if (!!(Desc.Flags & RAYTRACING_BUILD_AS_PREFER_FAST_TRACE) + !!(Desc.Flags & RAYTRACING_BUILD_AS_PREFER_FAST_BUILD))
+ {
+ LOG_TLAS_ERROR_AND_THROW("Used incompatible flags: RAYTRACING_BUILD_AS_PREFER_FAST_TRACE and RAYTRACING_BUILD_AS_PREFER_FAST_BUILD");
+ }
+
+#undef LOG_TLAS_ERROR_AND_THROW
+ }
+
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelAS, TDeviceObjectBase)
+
+protected:
+ struct InstanceDesc
+ {
+ Uint32 contributionToHitGroupIndex = 0;
+ mutable RefCntAutoPtr<IBottomLevelAS> pBLAS;
+ };
+
+ StringPool m_StringPool;
+ std::map<StringView, InstanceDesc> m_Instances;
+};
+
+} // namespace Diligent