diff options
| author | azhirnov <zh1dron@gmail.com> | 2020-10-04 20:23:28 +0000 |
|---|---|---|
| committer | azhirnov <zh1dron@gmail.com> | 2020-10-04 20:32:25 +0000 |
| commit | 7838459ef71fe5f0979f30df8348a6981363d6c8 (patch) | |
| tree | 0fea27225f76476cd5e19f0b11e4c574040f7bfb /Graphics/GraphicsEngine | |
| parent | Added dummy implementation for D3D11, D3D12, OpenGL (diff) | |
| download | DiligentCore-7838459ef71fe5f0979f30df8348a6981363d6c8.tar.gz DiligentCore-7838459ef71fe5f0979f30df8348a6981363d6c8.zip | |
Added Vulkan implementation
Diffstat (limited to 'Graphics/GraphicsEngine')
| -rw-r--r-- | Graphics/GraphicsEngine/include/BottomLevelASBase.hpp | 194 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/include/DeviceContextBase.hpp | 371 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/include/RenderDeviceBase.hpp | 17 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp | 96 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/include/TopLevelASBase.hpp | 147 |
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 |
