From 135d5dc6743fc89d7a19c539fa06eca33506f51b Mon Sep 17 00:00:00 2001 From: azhirnov Date: Wed, 28 Oct 2020 19:33:03 +0300 Subject: added ray tracing implementation for dx12 and vulkan --- .../src/GraphicsAccessories.cpp | 6 +- .../GraphicsEngine/include/BottomLevelASBase.hpp | 34 ++- .../GraphicsEngine/include/DeviceContextBase.hpp | 192 ++++++++++--- .../include/ShaderBindingTableBase.hpp | 105 ++++++- Graphics/GraphicsEngine/include/TopLevelASBase.hpp | 48 +++- Graphics/GraphicsEngine/interface/BottomLevelAS.h | 25 +- Graphics/GraphicsEngine/interface/DeviceContext.h | 155 ++++++++++- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 128 ++------- Graphics/GraphicsEngine/interface/PipelineState.h | 39 +++ .../GraphicsEngine/interface/ShaderBindingTable.h | 8 +- Graphics/GraphicsEngine/interface/TopLevelAS.h | 25 +- Graphics/GraphicsEngine/src/BufferBase.cpp | 2 +- .../include/DeviceContextD3D11Impl.hpp | 4 + .../src/DeviceContextD3D11Impl.cpp | 61 ++-- Graphics/GraphicsEngineD3D12/CMakeLists.txt | 9 + .../include/BottomLevelASD3D12Impl.hpp | 74 +++++ .../include/BufferD3D12Impl.hpp | 6 + .../GraphicsEngineD3D12/include/CommandContext.hpp | 157 ++++------- .../include/D3D12ResourceBase.hpp | 2 +- .../include/D3D12TypeConversions.hpp | 4 + .../include/DeviceContextD3D12Impl.hpp | 21 +- .../include/FramebufferD3D12Impl.hpp | 2 +- .../include/RenderPassD3D12Impl.hpp | 2 +- .../include/ShaderBindingTableD3D12Impl.hpp | 79 ++++++ .../include/TopLevelASD3D12Impl.hpp | 83 ++++++ .../interface/BottomLevelASD3D12.h | 70 +++++ .../interface/ShaderBindingTableD3D12.h | 71 +++++ .../interface/TopLevelASD3D12.h | 77 +++++ .../src/BottomLevelASD3D12Impl.cpp | 152 ++++++++++ .../GraphicsEngineD3D12/src/BufferD3D12Impl.cpp | 4 +- .../GraphicsEngineD3D12/src/CommandContext.cpp | 99 +++++-- .../src/D3D12TypeConversions.cpp | 70 ++++- .../src/DeviceContextD3D12Impl.cpp | 274 +++++++++++++++++- Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp | 2 +- .../src/PipelineStateD3D12Impl.cpp | 8 +- .../src/RenderDeviceD3D12Impl.cpp | 33 ++- Graphics/GraphicsEngineD3D12/src/RootSignature.cpp | 15 + .../src/ShaderBindingTableD3D12Impl.cpp | 202 ++++++++++++++ .../src/ShaderResourceLayoutD3D12.cpp | 30 ++ .../src/TopLevelASD3D12Impl.cpp | 115 ++++++++ .../include/DeviceContextGLImpl.hpp | 4 + .../include/BottomLevelASVkImpl.hpp | 11 + .../include/DescriptorPoolManager.hpp | 18 +- .../include/DeviceContextVkImpl.hpp | 29 ++ .../include/RenderDeviceVkImpl.hpp | 8 +- .../include/ShaderBindingTableVkImpl.hpp | 53 +--- .../include/TopLevelASVkImpl.hpp | 15 +- .../include/VulkanTypeConversions.hpp | 5 +- .../VulkanUtilities/VulkanCommandBuffer.hpp | 67 ++++- .../VulkanUtilities/VulkanLogicalDevice.hpp | 7 +- .../VulkanUtilities/VulkanMemoryManager.hpp | 31 ++- .../interface/BottomLevelASVk.h | 3 +- .../interface/ShaderBindingTableVk.h | 11 +- .../GraphicsEngineVulkan/interface/TopLevelASVk.h | 6 +- .../src/BottomLevelASVkImpl.cpp | 10 +- Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp | 14 +- .../src/CommandPoolManager.cpp | 7 +- .../src/DescriptorPoolManager.cpp | 35 +++ .../src/DeviceContextVkImpl.cpp | 309 +++++++++++++++++---- .../src/PipelineStateVkImpl.cpp | 20 +- .../GraphicsEngineVulkan/src/QueryManagerVk.cpp | 2 +- Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp | 2 +- .../src/ShaderBindingTableVkImpl.cpp | 187 +++++++------ .../src/ShaderResourceCacheVk.cpp | 63 ++--- .../src/ShaderResourceLayoutVk.cpp | 35 +-- .../GraphicsEngineVulkan/src/SwapChainVkImpl.cpp | 31 ++- .../GraphicsEngineVulkan/src/TextureVkImpl.cpp | 16 +- .../GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp | 8 +- .../src/VulkanTypeConversions.cpp | 65 ++++- .../GraphicsEngineVulkan/src/VulkanUploadHeap.cpp | 2 +- .../src/VulkanUtilities/VulkanCommandBuffer.cpp | 87 +++++- .../src/VulkanUtilities/VulkanLogicalDevice.cpp | 12 +- .../src/VulkanUtilities/VulkanMemoryManager.cpp | 30 +- .../VulkanUtilities/VulkanRayTracingKHRviaNV.cpp | 123 ++++---- 74 files changed, 3033 insertions(+), 786 deletions(-) create mode 100644 Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp create mode 100644 Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp create mode 100644 Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp create mode 100644 Graphics/GraphicsEngineD3D12/interface/BottomLevelASD3D12.h create mode 100644 Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h create mode 100644 Graphics/GraphicsEngineD3D12/interface/TopLevelASD3D12.h create mode 100644 Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp create mode 100644 Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp create mode 100644 Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp (limited to 'Graphics') diff --git a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp index 918b81ae..0617ca59 100644 --- a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp +++ b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp @@ -1055,7 +1055,8 @@ const Char* GetResourceStateFlagString(RESOURCE_STATE State) case RESOURCE_STATE_RESOLVE_SOURCE: return "RESOLVE_SOURCE"; case RESOURCE_STATE_INPUT_ATTACHMENT: return "INPUT_ATTACHMENT"; case RESOURCE_STATE_PRESENT: return "PRESENT"; - case RESOURCE_STATE_BUILD_AS: return "BUILD_AS"; + case RESOURCE_STATE_BUILD_AS_READ: return "BUILD_AS_READ"; + case RESOURCE_STATE_BUILD_AS_WRITE: return "BUILD_AS_WRITE"; case RESOURCE_STATE_RAY_TRACING: return "RAY_TRACING"; // clang-format on default: @@ -1204,7 +1205,8 @@ if ( (State & ExclusiveState) != 0 && (State & ~ExclusiveState) != 0 )\ VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_COPY_DEST); VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_RESOLVE_DEST); VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_PRESENT); - VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_BUILD_AS); + VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_BUILD_AS_READ); + VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_BUILD_AS_WRITE); VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_RAY_TRACING); #undef VERIFY_EXCLUSIVE_STATE // clang-format on diff --git a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp index 879d73ab..9f37fb3f 100644 --- a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp +++ b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp @@ -106,7 +106,7 @@ public: else if (Desc.pBoxes != nullptr) { size_t StringPoolSize = 0; - for (Uint32 i = 0; i < Desc.TriangleCount; ++i) + for (Uint32 i = 0; i < Desc.BoxCount; ++i) { if (Desc.pBoxes[i].GeometryName == nullptr) LOG_ERROR_AND_THROW("Geometry name can not be null!"); @@ -124,7 +124,7 @@ public: this->m_Desc.pTriangles = nullptr; // copy strings - for (Uint32 i = 0; i < Desc.TriangleCount; ++i) + for (Uint32 i = 0; i < Desc.BoxCount; ++i) { pBoxes[i].GeometryName = m_StringPool.CopyString(pBoxes[i].GeometryName); bool IsUniqueName = m_NameToIndex.emplace(pBoxes[i].GeometryName, i).second; @@ -147,7 +147,9 @@ public: } } - virtual Uint32 DILIGENT_CALL_TYPE GetGeometryIndex(const char* Name) const override + static constexpr Uint32 InvalidGeometryIndex = ~0u; + + virtual Uint32 DILIGENT_CALL_TYPE GetGeometryIndex(const char* Name) const override final { VERIFY_EXPR(Name != nullptr && Name[0] != '\0'); @@ -156,7 +158,29 @@ public: return iter->second; UNEXPECTED("Can't find geometry with specified name"); - return ~0u; // AZ TODO + return InvalidGeometryIndex; + } + + virtual void DILIGENT_CALL_TYPE SetState(RESOURCE_STATE State) override final + { + this->m_State = State; + } + + virtual RESOURCE_STATE DILIGENT_CALL_TYPE GetState() const override final + { + return this->m_State; + } + + bool IsInKnownState() const + { + return this->m_State != RESOURCE_STATE_UNKNOWN; + } + + bool CheckState(RESOURCE_STATE State) const + { + VERIFY((State & (State - 1)) == 0, "Single state is expected"); + VERIFY(IsInKnownState(), "BLAS state is unknown"); + return (this->m_State & State) == State; } protected: @@ -185,6 +209,8 @@ protected: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BottomLevelAS, TDeviceObjectBase) protected: + RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN; + std::unordered_map m_NameToIndex; StringPool m_StringPool; diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index c16219da..0d98bae3 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -78,6 +78,8 @@ public: using QueryImplType = typename ImplementationTraits::QueryType; using FramebufferImplType = typename ImplementationTraits::FramebufferType; using RenderPassImplType = typename ImplementationTraits::RenderPassType; + using BottomLevelASType = typename ImplementationTraits::BottomLevelASType; + using TopLevelASType = typename ImplementationTraits::TopLevelASType; /// \param pRefCounters - reference counters object that controls the lifetime of this device context. /// \param pRenderDevice - render device. @@ -253,8 +255,10 @@ protected: void DvpVerifyRenderTargets()const; void DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier)const; - bool DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName)const; - bool DvpVerifyBufferState (const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName)const; + bool DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName)const; + bool DvpVerifyBufferState (const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName)const; + bool DvpVerifyBLASState (const BottomLevelASType& BLAS, RESOURCE_STATE RequiredState, const char* OperationName)const; + bool DvpVerifyTLASState (const TopLevelASType& TLAS, RESOURCE_STATE RequiredState, const char* OperationName)const; #else bool DvpVerifyDrawArguments (const DrawAttribs& Attribs)const {return true;} bool DvpVerifyDrawIndexedArguments (const DrawIndexedAttribs& Attribs)const {return true;} @@ -268,8 +272,10 @@ protected: void DvpVerifyRenderTargets()const {} void DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier)const {} - bool DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;} - bool DvpVerifyBufferState (const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;} + bool DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;} + bool DvpVerifyBufferState (const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;} + bool DvpVerifyBLASState (const BottomLevelASType& BLAS, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;} + bool DvpVerifyTLASState (const TopLevelASType& TLAS, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;} // clang-format on #endif @@ -279,8 +285,6 @@ protected: bool CopyTLAS(const CopyTLASAttribs& Attribs, int); bool TraceRays(const TraceRaysAttribs& Attribs, int); - static const Uint32 TLASInstanceDataSize = 64; // bytes - /// Strong reference to the device. RefCntAutoPtr m_pDevice; @@ -1803,15 +1807,19 @@ template void DeviceContextBase:: DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier) const { - DEV_CHECK_ERR((Barrier.pTexture != nullptr) ^ (Barrier.pBuffer != nullptr), "Exactly one of pTexture or pBuffer members of StateTransitionDesc must not be null"); + DEV_CHECK_ERR(Barrier.pResource != nullptr, "pResource must not be null"); DEV_CHECK_ERR(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "New resource state can't be unknown"); RESOURCE_STATE OldState = RESOURCE_STATE_UNKNOWN; - if (Barrier.pTexture) + + RefCntAutoPtr pTexture{Barrier.pResource, IID_Texture}; + RefCntAutoPtr pBuffer{Barrier.pResource, IID_Buffer}; + + if (pTexture) { - const auto& TexDesc = Barrier.pTexture->GetDesc(); + const auto& TexDesc = pTexture->GetDesc(); DEV_CHECK_ERR(VerifyResourceStates(Barrier.NewState, true), "Invlaid new state specified for texture '", TexDesc.Name, "'"); - OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : Barrier.pTexture->GetState(); + OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pTexture->GetState(); DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of texture '", TexDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); @@ -1842,17 +1850,17 @@ void DeviceContextBase:: "Failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device"); } } - else if (Barrier.pBuffer) + else if (pBuffer) { - const auto& BuffDesc = Barrier.pBuffer->GetDesc(); + const auto& BuffDesc = pBuffer->GetDesc(); DEV_CHECK_ERR(VerifyResourceStates(Barrier.NewState, false), "Invlaid new state specified for buffer '", BuffDesc.Name, "'"); - OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : Barrier.pBuffer->GetState(); + OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pBuffer->GetState(); 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 + UNEXPECTED("unsupported resource type"); } if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS) @@ -1896,6 +1904,35 @@ bool DeviceContextBase:: return true; } +template +bool DeviceContextBase:: + DvpVerifyBLASState(const BottomLevelASType& BLAS, RESOURCE_STATE RequiredState, const char* OperationName) const +{ + if (BLAS.IsInKnownState() && !BLAS.CheckState(RequiredState)) + { + LOG_ERROR_MESSAGE(OperationName, " requires BLAS '", BLAS.GetDesc().Name, "' to be transitioned to ", GetResourceStateString(RequiredState), + " state. Actual BLAS state: ", GetResourceStateString(BLAS.GetState()), + ". Use appropriate state transiton flags or explicitly transition the BLAS using IDeviceContext::TransitionResourceStates() method."); + return false; + } + + return true; +} + +template +bool DeviceContextBase:: + DvpVerifyTLASState(const TopLevelASType& TLAS, RESOURCE_STATE RequiredState, const char* OperationName) const +{ + if (TLAS.IsInKnownState() && !TLAS.CheckState(RequiredState)) + { + LOG_ERROR_MESSAGE(OperationName, " requires TLAS '", TLAS.GetDesc().Name, "' to be transitioned to ", GetResourceStateString(RequiredState), + " state. Actual TLAS state: ", GetResourceStateString(TLAS.GetState()), + ". Use appropriate state transiton flags or explicitly transition the TLAS using IDeviceContext::TransitionResourceStates() method."); + return false; + } + + return true; +} #endif // DILIGENT_DEVELOPMENT template @@ -1913,7 +1950,7 @@ bool DeviceContextBase::BuildBLAS(const BLA return false; } - if ((Attribs.pTriangleData != nullptr) ^ (Attribs.pBoxData != nullptr)) + if (!((Attribs.pTriangleData != nullptr) ^ (Attribs.pBoxData != nullptr))) { LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: exactly one of pTriangles and pBoxes must be defined"); return false; @@ -1931,39 +1968,93 @@ bool DeviceContextBase::BuildBLAS(const BLA return false; } +#ifdef DILIGENT_DEVELOPMENT for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i) { - if (Attribs.pTriangleData[i].pVertexBuffer == nullptr) + const auto& tri = Attribs.pTriangleData[i]; + const Uint32 VertexSize = GetValueSize(tri.VertexValueType) * tri.VertexComponentCount; + const Uint32 VertexDataSize = tri.VertexStride * tri.VertexCount; + + if (tri.VertexValueType >= VT_NUM_TYPES) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].VertexValueType must be valid type"); + return false; + } + + if (tri.VertexComponentCount != 2 && tri.VertexComponentCount != 3) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].VertexComponentCount must be 2 or 3"); + return false; + } + + if (tri.VertexStride < VertexSize) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].VertexStride must be at least ", VertexSize, " bytes"); + return false; + } + + if (tri.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) + if ((tri.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 (tri.VertexOffset + VertexDataSize > tri.pVertexBuffer->GetDesc().uiSizeInBytes) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].pVertexBuffer is too small for specified VertexStride and VertexCount"); + return false; + } + + if (tri.IndexType != VT_UNDEFINED) { - if (Attribs.pTriangleData[i].pIndexBuffer == nullptr) + if (tri.IndexType != VT_UINT16 && tri.IndexType != VT_UINT32) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].IndexType must not be VT_UNDEFINED, VT_UINT16 or VT_UINT32"); + return false; + } + + if (tri.IndexCount == 0 || (tri.IndexCount % 3 != 0)) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].IndexCount must be valid"); + return false; + } + + if (tri.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) + if ((tri.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; } + + const Uint32 IndexDataSize = tri.IndexCount * GetValueSize(tri.IndexType); + if (tri.IndexOffset + IndexDataSize > tri.pIndexBuffer->GetDesc().uiSizeInBytes) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].pIndexBuffer is too small for specified IndexType and IndexCount"); + return false; + } + } + else + { + VERIFY(tri.pIndexBuffer == nullptr, + "IDeviceContext::BuildBLAS: pTriangleData[", i, "].pIndexBuffer must be null if IndexType is VT_UNDEFINED"); + VERIFY(tri.IndexCount == 0, + "IDeviceContext::BuildBLAS: pTriangleData[", i, "].IndexCount must be zero if IndexType is VT_UNDEFINED"); } - // AZ TODO: check AllosTransforms flags in create info - if (Attribs.pTriangleData[i].pTransformBuffer != nullptr) + if (tri.pTransformBuffer != nullptr) { - if ((Attribs.pTriangleData[i].pTransformBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING) + if ((tri.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; @@ -1973,13 +2064,22 @@ bool DeviceContextBase::BuildBLAS(const BLA for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i) { - if (Attribs.pBoxData[i].pBoxBuffer == nullptr) + const auto& box = Attribs.pBoxData[i]; + const Uint32 BoxSize = sizeof(float) * 6; + + if (box.BoxStride < BoxSize) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBoxData[", i, "].BoxStride must be at least ", BoxSize, " bytes"); + return false; + } + + if (box.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) + if ((box.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; @@ -2019,6 +2119,7 @@ bool DeviceContextBase::BuildBLAS(const BLA LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must be created with BIND_RAY_TRACING flag"); return false; } +#endif // DILIGENT_DEVELOPMENT return true; } @@ -2044,18 +2145,19 @@ bool DeviceContextBase::BuildTLAS(const TLA return false; } - if (Attribs.pInstancesBuffer == nullptr) + if (Attribs.pInstanceBuffer == nullptr) { LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceaBuffer must not be null"); return false; } - if (Attribs.HitShadersPerInstance > 0) + if (Attribs.HitShadersPerInstance == 0) { LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: HitShadersPerInstance must be greater than 0"); return false; } +#ifdef DILIGENT_DEVELOPMENT const auto& TLASDesc = Attribs.pTLAS->GetDesc(); if (Attribs.InstanceCount > TLASDesc.MaxInstanceCount) @@ -2064,14 +2166,16 @@ bool DeviceContextBase::BuildTLAS(const TLA return false; } - const auto& InstDesc = Attribs.pInstancesBuffer->GetDesc(); - const size_t InstDataSize = Attribs.InstanceCount * TLASInstanceDataSize; + const auto& InstDesc = Attribs.pInstanceBuffer->GetDesc(); + const size_t InstDataSize = Attribs.InstanceCount * TLAS_INSTANCE_DATA_SIZE; + Uint32 AutoOffsetCounter = 0; // 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); + VERIFY_EXPR((Attribs.pInstances[i].CustomId & ~0x00FFFFFF) == 0); + VERIFY_EXPR(Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO || + (Attribs.pInstances[i].ContributionToHitGroupIndex & ~0x00FFFFFF) == 0); if (Attribs.pInstances[i].InstanceName == nullptr) { @@ -2084,15 +2188,24 @@ bool DeviceContextBase::BuildTLAS(const TLA LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances[", i, "].pBLAS must not be null"); return false; } + + if (Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) + ++AutoOffsetCounter; + } + + if (AutoOffsetCounter != 0 && AutoOffsetCounter != Attribs.InstanceCount) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: exactly all pInstances[i].ContributionToHitGroupIndex must be TLAS_INSTANCE_OFFSET_AUTO or not"); + return false; } - if (Attribs.InstancesBufferOffset > InstDesc.uiSizeInBytes) + if (Attribs.InstanceBufferOffset > InstDesc.uiSizeInBytes) { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: InstancesBufferOffset is greater than buffer size"); + LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: InstanceBufferOffset is greater than buffer size"); return false; } - if (InstDesc.uiSizeInBytes - Attribs.InstancesBufferOffset > InstDataSize) + if (InstDesc.uiSizeInBytes - Attribs.InstanceBufferOffset > InstDataSize) { LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceaBuffer size is too small, ..."); return false; @@ -2123,6 +2236,7 @@ bool DeviceContextBase::BuildTLAS(const TLA LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must be created with BIND_RAY_TRACING flag"); return false; } +#endif // DILIGENT_DEVELOPMENT return true; } @@ -2142,6 +2256,7 @@ bool DeviceContextBase::CopyBLAS(const Copy return false; } +#ifdef DILIGENT_DEVELOPMENT if (Attribs.Mode == COPY_AS_MODE_CLONE) { auto& SrcDesc = Attribs.pSrc->GetDesc(); @@ -2192,13 +2307,15 @@ bool DeviceContextBase::CopyBLAS(const Copy return false; } } - return true; } else { LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: unknown Mode"); return false; } +#endif // DILIGENT_DEVELOPMENT + + return true; } template @@ -2216,6 +2333,7 @@ bool DeviceContextBase::CopyTLAS(const Copy return false; } +#ifdef DILIGENT_DEVELOPMENT if (Attribs.Mode == COPY_AS_MODE_CLONE) { auto& SrcDesc = Attribs.pSrc->GetDesc(); @@ -2227,13 +2345,15 @@ bool DeviceContextBase::CopyTLAS(const Copy 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; } +#endif // DILIGENT_DEVELOPMENT + + return true; } template diff --git a/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp index cce40b11..155ecb66 100644 --- a/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp @@ -47,7 +47,7 @@ namespace Diligent /// (Diligent::IShaderBindingTableD3D12 or Diligent::IShaderBindingTableVk). /// \tparam RenderDeviceImplType - type of the render device implementation /// (Diligent::RenderDeviceD3D12Impl or Diligent::RenderDeviceVkImpl) -template +template class ShaderBindingTableBase : public DeviceObjectBase { public: @@ -71,6 +71,100 @@ public: { } + void BindRayGenShader(const char* ShaderGroupName, const void* Data, Uint32 DataSize) override final + { + VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + + this->m_RayGenShaderRecord.resize(this->m_ShaderRecordStride); + ValidatedCast(this->m_Desc.pPSO)->CopyShaderHandle(ShaderGroupName, this->m_RayGenShaderRecord.data(), this->m_ShaderRecordStride); + this->m_Changed = true; + } + + void BindMissShader(const char* ShaderGroupName, Uint32 MissIndex, const void* Data, Uint32 DataSize) override final + { + VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + + const Uint32 Offset = MissIndex * this->m_ShaderRecordStride; + this->m_MissShadersRecord.resize(std::max(this->m_MissShadersRecord.size(), Offset + this->m_ShaderRecordStride)); + + ValidatedCast(this->m_Desc.pPSO)->CopyShaderHandle(ShaderGroupName, this->m_MissShadersRecord.data() + Offset, this->m_ShaderRecordStride); + this->m_Changed = true; + } + + void BindHitGroup(ITopLevelAS* pTLAS, + const char* InstanceName, + const char* GeometryName, + Uint32 RayOffsetInHitGroupIndex, + const char* ShaderGroupName, + const void* Data, + Uint32 DataSize) override final + { + VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + 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); + + const Uint32 InstanceIndex = Desc.ContributionToHitGroupIndex; + const Uint32 GeometryIndex = Desc.pBLAS->GetGeometryIndex(GeometryName); + const Uint32 Index = InstanceIndex + GeometryIndex * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; + const Uint32 Offset = Index * this->m_ShaderRecordStride; + + this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), Offset + this->m_ShaderRecordStride)); + + ValidatedCast(this->m_Desc.pPSO)->CopyShaderHandle(ShaderGroupName, this->m_HitGroupsRecord.data() + Offset, this->m_ShaderRecordStride); + this->m_Changed = true; + } + + void BindHitGroups(ITopLevelAS* pTLAS, + const char* InstanceName, + Uint32 RayOffsetInHitGroupIndex, + const char* ShaderGroupName, + const void* Data, + Uint32 DataSize) override final + { + VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + 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); + + const Uint32 InstanceIndex = Desc.ContributionToHitGroupIndex; + const auto& GeometryDesc = Desc.pBLAS->GetDesc(); + const Uint32 GeometryCount = GeometryDesc.BoxCount + GeometryDesc.TriangleCount; + const Uint32 BeginIndex = InstanceIndex + 0 * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; + const Uint32 EndIndex = InstanceIndex + GeometryCount * this->m_Desc.HitShadersPerInstance + RayOffsetInHitGroupIndex; + PipelineStateImplType* pPSO = ValidatedCast(this->m_Desc.pPSO); + + this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), EndIndex * this->m_ShaderRecordStride)); + + for (Uint32 i = 0; i < GeometryCount; ++i) + { + Uint32 Offset = (BeginIndex + i) * this->m_ShaderRecordStride; + pPSO->CopyShaderHandle(ShaderGroupName, this->m_HitGroupsRecord.data() + Offset, this->m_ShaderRecordStride); + } + this->m_Changed = true; + } + + void BindCallableShader(const char* ShaderGroupName, + Uint32 CallableIndex, + const void* Data, + Uint32 DataSize) override final + { + VERIFY(Data == nullptr && DataSize == 0, "not supported yet"); + + const Uint32 Offset = CallableIndex * this->m_ShaderRecordStride; + this->m_CallableShadersRecord.resize(std::max(this->m_CallableShadersRecord.size(), Offset + this->m_ShaderRecordStride)); + + ValidatedCast(this->m_Desc.pPSO)->CopyShaderHandle(ShaderGroupName, this->m_CallableShadersRecord.data() + Offset, this->m_ShaderRecordStride); + this->m_Changed = true; + } + protected: static void ValidateShaderBindingTableDesc(const ShaderBindingTableDesc& Desc) { @@ -92,10 +186,13 @@ protected: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderBindingTable, TDeviceObjectBase) protected: - StringPool m_StringPool; + std::vector m_RayGenShaderRecord; + std::vector m_MissShadersRecord; + std::vector m_CallableShadersRecord; + std::vector m_HitGroupsRecord; - std::unordered_map m_NameToIndex; - std::unordered_map m_Instances; + Uint32 m_ShaderRecordStride = 0; + bool m_Changed = true; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngine/include/TopLevelASBase.hpp b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp index 2d2049af..ab56636f 100644 --- a/Graphics/GraphicsEngine/include/TopLevelASBase.hpp +++ b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp @@ -71,7 +71,7 @@ public: { } - void SetInstanceData(const TLASBuildInstanceData* pInstances, Uint32 InstanceCount) + void SetInstanceData(const TLASBuildInstanceData* pInstances, Uint32 InstanceCount, Uint32 HitShadersPerInstance) { m_Instances.clear(); m_StringPool.Release(); @@ -84,22 +84,31 @@ public: m_StringPool.Reserve(StringPoolSize, GetRawAllocator()); + Uint32 InstanceOffset = 0; + 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.ContributionToHitGroupIndex = inst.ContributionToHitGroupIndex; Desc.pBLAS = inst.pBLAS; + if (Desc.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) + { + Desc.ContributionToHitGroupIndex = InstanceOffset; + auto& BLASDesc = Desc.pBLAS->GetDesc(); + InstanceOffset += (BLASDesc.TriangleCount + BLASDesc.BoxCount) * HitShadersPerInstance; + } + bool IsUniqueName = m_Instances.emplace(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 + virtual TLASInstanceDesc DILIGENT_CALL_TYPE GetInstanceDesc(const char* Name) const override final { VERIFY_EXPR(Name != nullptr && Name[0] != '\0'); @@ -108,7 +117,7 @@ public: auto iter = m_Instances.find(Name); if (iter != m_Instances.end()) { - Result.ContributionToHitGroupIndex = iter->second.contributionToHitGroupIndex; + Result.ContributionToHitGroupIndex = iter->second.ContributionToHitGroupIndex; Result.pBLAS = iter->second.pBLAS; } else @@ -119,6 +128,28 @@ public: return Result; } + virtual void DILIGENT_CALL_TYPE SetState(RESOURCE_STATE State) override final + { + this->m_State = State; + } + + virtual RESOURCE_STATE DILIGENT_CALL_TYPE GetState() const override final + { + return this->m_State; + } + + bool IsInKnownState() const + { + return this->m_State != RESOURCE_STATE_UNKNOWN; + } + + bool CheckState(RESOURCE_STATE State) const + { + VERIFY((State & (State - 1)) == 0, "Single state is expected"); + VERIFY(IsInKnownState(), "TLAS state is unknown"); + return (this->m_State & State) == State; + } + protected: static void ValidateTopLevelASDesc(const TopLevelASDesc& Desc) { @@ -141,14 +172,15 @@ protected: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelAS, TDeviceObjectBase) protected: + RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN; + + StringPool m_StringPool; + struct InstanceDesc { - Uint32 contributionToHitGroupIndex = 0; + Uint32 ContributionToHitGroupIndex = 0; mutable RefCntAutoPtr pBLAS; }; - - StringPool m_StringPool; - std::unordered_map m_Instances; }; diff --git a/Graphics/GraphicsEngine/interface/BottomLevelAS.h b/Graphics/GraphicsEngine/interface/BottomLevelAS.h index cc8c4aec..264720ff 100644 --- a/Graphics/GraphicsEngine/interface/BottomLevelAS.h +++ b/Graphics/GraphicsEngine/interface/BottomLevelAS.h @@ -200,6 +200,25 @@ DILIGENT_BEGIN_INTERFACE(IBottomLevelAS, IDeviceObject) /// AZ TODO 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 + VIRTUAL void* METHOD(GetNativeHandle)(THIS) PURE; + + /// Sets the acceleration structure usage state. + + /// \note This method does not perform state transition, but + /// resets the internal acceleration structure state to the given value. + /// This method should be used after the application finished + /// manually managing the acceleration structure state and wants to hand over + /// state management back to the engine. + VIRTUAL void METHOD(SetState)(THIS_ + RESOURCE_STATE State) PURE; + + /// Returns the internal acceleration structure state + VIRTUAL RESOURCE_STATE METHOD(GetState)(THIS) CONST PURE; }; DILIGENT_END_INTERFACE @@ -209,7 +228,11 @@ DILIGENT_END_INTERFACE // clang-format off -# define IBottomLevelAS_GetGeometryIndex(This, ...) CALL_IFACE_METHOD(BottomLevelAS, GetGeometryIndex, This, __VA_ARGS__) +# 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) // clang-format on diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index a294b066..04ff3030 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -809,7 +809,7 @@ struct BLASBuildTriangleData Uint32 IndexOffset DEFAULT_INITIALIZER(0); /// AZ TODO - Uint32 IndexCount DEFAULT_INITIALIZER(0); + Uint32 IndexCount DEFAULT_INITIALIZER(0); // AZ TODO: use PrimitveCount ? /// AZ TODO VALUE_TYPE IndexType DEFAULT_INITIALIZER(VT_UNDEFINED); // optional, value may be taken from declaration @@ -871,6 +871,9 @@ struct BLASBuildAttribs /// AZ TODO RESOURCE_STATE_TRANSITION_MODE BLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); + /// AZ TODO + RESOURCE_STATE_TRANSITION_MODE GeometryTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); + /// AZ TODO BLASBuildTriangleData const* pTriangleData DEFAULT_INITIALIZER(nullptr); @@ -903,6 +906,9 @@ typedef struct BLASBuildAttribs BLASBuildAttribs; /// AZ TODO static const Uint32 TLAS_INSTANCE_OFFSET_AUTO = ~0u; +/// AZ TODO +static const Uint32 TLAS_INSTANCE_DATA_SIZE = 64; + /// AZ TODO struct TLASBuildInstanceData @@ -917,7 +923,7 @@ struct TLASBuildInstanceData float Transform[3][4] DEFAULT_INITIALIZER({}); /// AZ TODO - Uint32 customId DEFAULT_INITIALIZER(0); // 24 bits, in shader: gl_InstanceCustomIndexNV for GLSL, InstanceID() for HLSL + Uint32 CustomId DEFAULT_INITIALIZER(0); // 24 bits, in shader: gl_InstanceCustomIndexNV for GLSL, InstanceID() for HLSL /// AZ TODO RAYTRACING_INSTANCE_FLAGS Flags DEFAULT_INITIALIZER(RAYTRACING_INSTANCE_NONE); @@ -926,7 +932,7 @@ struct TLASBuildInstanceData Uint8 Mask DEFAULT_INITIALIZER(0xFF); // visibility mask for the geometry, the instance may only be hit if rayMask & instance.mask != 0 /// AZ TODO - Uint32 contributionToHitGroupIndex DEFAULT_INITIALIZER(TLAS_INSTANCE_OFFSET_AUTO); // used when TLAS created with SHADER_BINDING_USER_DEFINED, see IShaderBindingTangle::BindAll() + Uint32 ContributionToHitGroupIndex DEFAULT_INITIALIZER(TLAS_INSTANCE_OFFSET_AUTO); // used when TLAS created with SHADER_BINDING_USER_DEFINED, see IShaderBindingTangle::BindAll() #if DILIGENT_CPP_INTERFACE /// AZ TODO @@ -940,37 +946,40 @@ typedef struct TLASBuildInstanceData TLASBuildInstanceData; struct TLASBuildAttribs { /// AZ TODO - ITopLevelAS* pTLAS DEFAULT_INITIALIZER(nullptr); + ITopLevelAS* pTLAS DEFAULT_INITIALIZER(nullptr); /// AZ TODO - RESOURCE_STATE_TRANSITION_MODE TLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); + RESOURCE_STATE_TRANSITION_MODE TLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); /// AZ TODO - TLASBuildInstanceData const* pInstances DEFAULT_INITIALIZER(nullptr); + RESOURCE_STATE_TRANSITION_MODE BLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); + + /// AZ TODO + TLASBuildInstanceData const* pInstances DEFAULT_INITIALIZER(nullptr); /// AZ TODO - Uint32 InstanceCount DEFAULT_INITIALIZER(0); + Uint32 InstanceCount DEFAULT_INITIALIZER(0); /// AZ TODO - IBuffer* pInstancesBuffer DEFAULT_INITIALIZER(nullptr); + IBuffer* pInstanceBuffer DEFAULT_INITIALIZER(nullptr); /// AZ TODO - Uint32 InstancesBufferOffset DEFAULT_INITIALIZER(0); + Uint32 InstanceBufferOffset DEFAULT_INITIALIZER(0); /// AZ TODO - RESOURCE_STATE_TRANSITION_MODE InstanceBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); + RESOURCE_STATE_TRANSITION_MODE InstanceBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); /// AZ TODO - Uint32 HitShadersPerInstance DEFAULT_INITIALIZER(1); + Uint32 HitShadersPerInstance DEFAULT_INITIALIZER(1); /// AZ TODO - IBuffer* pScratchBuffer DEFAULT_INITIALIZER(nullptr); + IBuffer* pScratchBuffer DEFAULT_INITIALIZER(nullptr); /// AZ TODO - Uint32 ScratchBufferOffset DEFAULT_INITIALIZER(0); + Uint32 ScratchBufferOffset DEFAULT_INITIALIZER(0); /// AZ TODO - RESOURCE_STATE_TRANSITION_MODE ScratchBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); + RESOURCE_STATE_TRANSITION_MODE ScratchBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); #if DILIGENT_CPP_INTERFACE /// AZ TODO @@ -1048,6 +1057,124 @@ struct TraceRaysAttribs typedef struct TraceRaysAttribs TraceRaysAttribs; +static const Uint32 REMAINING_MIP_LEVELS = 0xFFFFFFFFU; +static const Uint32 REMAINING_ARRAY_SLICES = 0xFFFFFFFFU; + +/// Resource state transition barrier description +struct StateTransitionDesc +{ + /// Resource to transition. + /// Can be ITexture, IBuffer, IBottomLevelAS, ITopLevelAS. + struct IDeviceObject* pResource DEFAULT_INITIALIZER(nullptr); + + /// When transitioning a texture, first mip level of the subresource range to transition. + Uint32 FirstMipLevel DEFAULT_INITIALIZER(0); + + /// When transitioning a texture, number of mip levels of the subresource range to transition. + Uint32 MipLevelsCount DEFAULT_INITIALIZER(REMAINING_MIP_LEVELS); + + /// When transitioning a texture, first array slice of the subresource range to transition. + Uint32 FirstArraySlice DEFAULT_INITIALIZER(0); + + /// When transitioning a texture, number of array slices of the subresource range to transition. + Uint32 ArraySliceCount DEFAULT_INITIALIZER(REMAINING_ARRAY_SLICES); + + /// Resource state before transition. If this value is RESOURCE_STATE_UNKNOWN, + /// internal resource state will be used, which must be defined in this case. + RESOURCE_STATE OldState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN); + + /// Resource state after transition. + RESOURCE_STATE NewState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN); + + /// State transition type, see Diligent::STATE_TRANSITION_TYPE. + + /// \note When issuing UAV barrier (i.e. OldState and NewState equal RESOURCE_STATE_UNORDERED_ACCESS), + /// TransitionType must be STATE_TRANSITION_TYPE_IMMEDIATE. + STATE_TRANSITION_TYPE TransitionType DEFAULT_INITIALIZER(STATE_TRANSITION_TYPE_IMMEDIATE); + + /// If set to true, the internal resource state will be set to NewState and the engine + /// will be able to take over the resource state management. In this case it is the + /// responsibility of the application to make sure that all subresources are indeed in + /// designated state. + /// If set to false, internal resource state will be unchanged. + /// \note When TransitionType is STATE_TRANSITION_TYPE_BEGIN, this member must be false. + bool UpdateResourceState DEFAULT_INITIALIZER(false); + +#if DILIGENT_CPP_INTERFACE + StateTransitionDesc()noexcept{} + + StateTransitionDesc(ITexture* _pTexture, + RESOURCE_STATE _OldState, + RESOURCE_STATE _NewState, + Uint32 _FirstMipLevel = 0, + Uint32 _MipLevelsCount = REMAINING_MIP_LEVELS, + Uint32 _FirstArraySlice = 0, + Uint32 _ArraySliceCount = REMAINING_ARRAY_SLICES, + STATE_TRANSITION_TYPE _TransitionType = STATE_TRANSITION_TYPE_IMMEDIATE, + bool _UpdateState = false)noexcept : + pResource {static_cast(_pTexture)}, + FirstMipLevel {_FirstMipLevel }, + MipLevelsCount {_MipLevelsCount }, + FirstArraySlice {_FirstArraySlice}, + ArraySliceCount {_ArraySliceCount}, + OldState {_OldState }, + NewState {_NewState }, + TransitionType {_TransitionType }, + UpdateResourceState {_UpdateState } + {} + + StateTransitionDesc(ITexture* _pTexture, + RESOURCE_STATE _OldState, + RESOURCE_STATE _NewState, + bool _UpdateState)noexcept : + StateTransitionDesc + { + _pTexture, + _OldState, + _NewState, + 0, + REMAINING_MIP_LEVELS, + 0, + REMAINING_ARRAY_SLICES, + STATE_TRANSITION_TYPE_IMMEDIATE, + _UpdateState + } + {} + + StateTransitionDesc(IBuffer* _pBuffer, + RESOURCE_STATE _OldState, + RESOURCE_STATE _NewState, + bool _UpdateState)noexcept : + pResource {static_cast(_pBuffer)}, + OldState {_OldState }, + NewState {_NewState }, + UpdateResourceState {_UpdateState} + {} + + StateTransitionDesc(IBottomLevelAS* _pBLAS, + RESOURCE_STATE _OldState, + RESOURCE_STATE _NewState, + bool _UpdateState)noexcept : + pResource {static_cast(_pBLAS)}, + OldState {_OldState }, + NewState {_NewState }, + UpdateResourceState {_UpdateState} + {} + + StateTransitionDesc(ITopLevelAS* _pTLAS, + RESOURCE_STATE _OldState, + RESOURCE_STATE _NewState, + bool _UpdateState)noexcept : + pResource {static_cast(_pTLAS)}, + OldState {_OldState }, + NewState {_NewState }, + UpdateResourceState {_UpdateState} + {} +#endif +}; +typedef struct StateTransitionDesc StateTransitionDesc; + + #define DILIGENT_INTERFACE_NAME IDeviceContext #include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 10a84f1d..093039bd 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -41,9 +41,6 @@ /// Graphics engine namespace DILIGENT_BEGIN_NAMESPACE(Diligent) -struct ITexture; -struct IBuffer; - /// Value type /// This enumeration describes value type. It is used by @@ -86,7 +83,7 @@ DILIGENT_TYPED_ENUM(BIND_FLAGS, Uint32) BIND_UNORDERED_ACCESS = 0x80L, ///< A buffer or a texture can be bound as an unordered access view BIND_INDIRECT_DRAW_ARGS = 0x100L, ///< A buffer can be bound as the source buffer for indirect draw commands BIND_INPUT_ATTACHMENT = 0x200L, ///< A texture can be used as render pass input attachment - BIND_RAY_TRACING = 0x400L, ///< AZ TODO + BIND_RAY_TRACING = 0x400L, ///< A buffer can be used as scratch buffer for acceleration structure building. BIND_FLAGS_LAST = 0x400L }; DEFINE_FLAG_ENUM_OPERATORS(BIND_FLAGS) @@ -1253,16 +1250,22 @@ typedef struct DisplayModeAttribs DisplayModeAttribs; DILIGENT_TYPED_ENUM(SWAP_CHAIN_USAGE_FLAGS, Uint32) { /// No allowed usage - SWAP_CHAIN_USAGE_NONE = 0x00L, + SWAP_CHAIN_USAGE_NONE = 0x00L, /// Swap chain can be used as render target ouput - SWAP_CHAIN_USAGE_RENDER_TARGET = 0x01L, + SWAP_CHAIN_USAGE_RENDER_TARGET = 0x01L, /// Swap chain images can be used as shader inputs - SWAP_CHAIN_USAGE_SHADER_INPUT = 0x02L, + SWAP_CHAIN_USAGE_SHADER_INPUT = 0x02L, /// Swap chain images can be used as source of copy operation - SWAP_CHAIN_USAGE_COPY_SOURCE = 0x04L + SWAP_CHAIN_USAGE_COPY_SOURCE = 0x04L, + + /// Swap chain images will define an unordered access view that will be used + /// for unordered read/write operations from the shaders + SWAP_CHAIN_USAGE_UNORDERED_ACCESS = 0x08L, + + SWAP_CHAIN_USAGE_LAST = SWAP_CHAIN_USAGE_UNORDERED_ACCESS, }; DEFINE_FLAG_ENUM_OPERATORS(SWAP_CHAIN_USAGE_FLAGS) @@ -2720,10 +2723,12 @@ DILIGENT_TYPED_ENUM(RESOURCE_STATE, Uint32) /// The resource is used for present RESOURCE_STATE_PRESENT = 0x10000, - RESOURCE_STATE_BUILD_AS = 0x20000, - RESOURCE_STATE_RAY_TRACING = 0x40000, + /// AZ TODO + RESOURCE_STATE_BUILD_AS_READ = 0x20000, + RESOURCE_STATE_BUILD_AS_WRITE = 0x40000, + RESOURCE_STATE_RAY_TRACING = 0x80000, - RESOURCE_STATE_MAX_BIT = 0x40000, + RESOURCE_STATE_MAX_BIT = RESOURCE_STATE_RAY_TRACING, RESOURCE_STATE_GENERIC_READ = RESOURCE_STATE_VERTEX_BUFFER | RESOURCE_STATE_CONSTANT_BUFFER | @@ -2753,105 +2758,4 @@ DILIGENT_TYPED_ENUM(STATE_TRANSITION_TYPE, Uint8) STATE_TRANSITION_TYPE_END }; -static const Uint32 REMAINING_MIP_LEVELS = 0xFFFFFFFFU; -static const Uint32 REMAINING_ARRAY_SLICES = 0xFFFFFFFFU; - -/// Resource state transition barrier description -struct StateTransitionDesc -{ - /// Texture to transition. - /// \note Exactly one of pTexture or pBuffer must be non-null. - struct ITexture* pTexture DEFAULT_INITIALIZER(nullptr); - - /// Buffer to transition. - /// \note Exactly one of pTexture or pBuffer must be non-null. - struct IBuffer* pBuffer DEFAULT_INITIALIZER(nullptr); - - /// When transitioning a texture, first mip level of the subresource range to transition. - Uint32 FirstMipLevel DEFAULT_INITIALIZER(0); - - /// When transitioning a texture, number of mip levels of the subresource range to transition. - Uint32 MipLevelsCount DEFAULT_INITIALIZER(REMAINING_MIP_LEVELS); - - /// When transitioning a texture, first array slice of the subresource range to transition. - Uint32 FirstArraySlice DEFAULT_INITIALIZER(0); - - /// When transitioning a texture, number of array slices of the subresource range to transition. - Uint32 ArraySliceCount DEFAULT_INITIALIZER(REMAINING_ARRAY_SLICES); - - /// Resource state before transition. If this value is RESOURCE_STATE_UNKNOWN, - /// internal resource state will be used, which must be defined in this case. - RESOURCE_STATE OldState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN); - - /// Resource state after transition. - RESOURCE_STATE NewState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN); - - /// State transition type, see Diligent::STATE_TRANSITION_TYPE. - - /// \note When issuing UAV barrier (i.e. OldState and NewState equal RESOURCE_STATE_UNORDERED_ACCESS), - /// TransitionType must be STATE_TRANSITION_TYPE_IMMEDIATE. - STATE_TRANSITION_TYPE TransitionType DEFAULT_INITIALIZER(STATE_TRANSITION_TYPE_IMMEDIATE); - - /// If set to true, the internal resource state will be set to NewState and the engine - /// will be able to take over the resource state management. In this case it is the - /// responsibility of the application to make sure that all subresources are indeed in - /// designated state. - /// If set to false, internal resource state will be unchanged. - /// \note When TransitionType is STATE_TRANSITION_TYPE_BEGIN, this member must be false. - bool UpdateResourceState DEFAULT_INITIALIZER(false); - -#if DILIGENT_CPP_INTERFACE - StateTransitionDesc()noexcept{} - - StateTransitionDesc(ITexture* _pTexture, - RESOURCE_STATE _OldState, - RESOURCE_STATE _NewState, - Uint32 _FirstMipLevel = 0, - Uint32 _MipLevelsCount = REMAINING_MIP_LEVELS, - Uint32 _FirstArraySlice = 0, - Uint32 _ArraySliceCount = REMAINING_ARRAY_SLICES, - STATE_TRANSITION_TYPE _TransitionType = STATE_TRANSITION_TYPE_IMMEDIATE, - bool _UpdateState = false)noexcept : - pTexture {_pTexture }, - FirstMipLevel {_FirstMipLevel }, - MipLevelsCount {_MipLevelsCount }, - FirstArraySlice {_FirstArraySlice}, - ArraySliceCount {_ArraySliceCount}, - OldState {_OldState }, - NewState {_NewState }, - TransitionType {_TransitionType }, - UpdateResourceState {_UpdateState } - {} - - StateTransitionDesc(ITexture* _pTexture, - RESOURCE_STATE _OldState, - RESOURCE_STATE _NewState, - bool _UpdateState)noexcept : - StateTransitionDesc - { - _pTexture, - _OldState, - _NewState, - 0, - REMAINING_MIP_LEVELS, - 0, - REMAINING_ARRAY_SLICES, - STATE_TRANSITION_TYPE_IMMEDIATE, - _UpdateState - } - {} - - StateTransitionDesc(IBuffer* _pBuffer, - RESOURCE_STATE _OldState, - RESOURCE_STATE _NewState, - bool _UpdateState)noexcept : - pBuffer {_pBuffer }, - OldState {_OldState }, - NewState {_NewState }, - UpdateResourceState {_UpdateState} - {} -#endif -}; -typedef struct StateTransitionDesc StateTransitionDesc; - DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index e45dc703..3afa83f2 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -223,6 +223,17 @@ struct RayTracingGeneralShaderGroup /// AZ TODO IShader* pShader DEFAULT_INITIALIZER(nullptr); + +#if DILIGENT_CPP_INTERFACE + RayTracingGeneralShaderGroup() noexcept + {} + + RayTracingGeneralShaderGroup(const char* _Name, + IShader* _pShader) noexcept: + Name {_Name }, + pShader{_pShader} + {} +#endif }; typedef struct RayTracingGeneralShaderGroup RayTracingGeneralShaderGroup; @@ -237,6 +248,19 @@ struct RayTracingTriangleHitShaderGroup /// AZ TODO IShader* pAnyHitShader DEFAULT_INITIALIZER(nullptr); // can be null + +#if DILIGENT_CPP_INTERFACE + RayTracingTriangleHitShaderGroup() noexcept + {} + + RayTracingTriangleHitShaderGroup(const char* _Name, + IShader* _pClosestHitShader, + IShader* _pAnyHitShader = nullptr) noexcept: + Name {_Name }, + pClosestHitShader{_pClosestHitShader}, + pAnyHitShader {_pAnyHitShader } + {} +#endif }; typedef struct RayTracingTriangleHitShaderGroup RayTracingTriangleHitShaderGroup; @@ -254,6 +278,21 @@ struct RayTracingProceduralHitShaderGroup /// AZ TODO IShader* pAnyHitShader DEFAULT_INITIALIZER(nullptr); // can be null + +#if DILIGENT_CPP_INTERFACE + RayTracingProceduralHitShaderGroup() noexcept + {} + + RayTracingProceduralHitShaderGroup(const char* _Name, + IShader* _pIntersectionShader, + IShader* _pClosestHitShader = nullptr, + IShader* _pAnyHitShader = nullptr) noexcept: + Name {_Name }, + pIntersectionShader{_pIntersectionShader}, + pClosestHitShader {_pClosestHitShader }, + pAnyHitShader {_pAnyHitShader } + {} +#endif }; typedef struct RayTracingProceduralHitShaderGroup RayTracingProceduralHitShaderGroup; diff --git a/Graphics/GraphicsEngine/interface/ShaderBindingTable.h b/Graphics/GraphicsEngine/interface/ShaderBindingTable.h index 514f9b7c..71fa25e4 100644 --- a/Graphics/GraphicsEngine/interface/ShaderBindingTable.h +++ b/Graphics/GraphicsEngine/interface/ShaderBindingTable.h @@ -157,10 +157,10 @@ DILIGENT_BEGIN_INTERFACE(IShaderBindingTable, IDeviceObject) /// AZ TODO VIRTUAL void METHOD(BindCallableShader)(THIS_ - Uint32 Index, - const char* ShaderName, - const void* Data DEFAULT_INITIALIZER(nullptr), - Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE; + const char* ShaderGroupName, + Uint32 CallableIndex, + const void* Data DEFAULT_INITIALIZER(nullptr), + Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE; /// AZ TODO VIRTUAL void METHOD(BindAll)(THIS_ diff --git a/Graphics/GraphicsEngine/interface/TopLevelAS.h b/Graphics/GraphicsEngine/interface/TopLevelAS.h index 0e427864..630f8ddd 100644 --- a/Graphics/GraphicsEngine/interface/TopLevelAS.h +++ b/Graphics/GraphicsEngine/interface/TopLevelAS.h @@ -120,6 +120,25 @@ DILIGENT_BEGIN_INTERFACE(ITopLevelAS, IDeviceObject) /// AZ TODO 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 + VIRTUAL void* METHOD(GetNativeHandle)(THIS) PURE; + + /// Sets the acceleration structure usage state. + + /// \note This method does not perform state transition, but + /// resets the internal acceleration structure state to the given value. + /// This method should be used after the application finished + /// manually managing the acceleration structure state and wants to hand over + /// state management back to the engine. + VIRTUAL void METHOD(SetState)(THIS_ + RESOURCE_STATE State) PURE; + + /// Returns the internal acceleration structure state + VIRTUAL RESOURCE_STATE METHOD(GetState)(THIS) CONST PURE; }; DILIGENT_END_INTERFACE @@ -129,7 +148,11 @@ DILIGENT_END_INTERFACE // clang-format off -# define ITopLevelAS_GetInstanceDesc(This, ...) CALL_IFACE_METHOD(TopLevelAS, GetInstanceDesc, This, __VA_ARGS__) +# 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) // clang-format on diff --git a/Graphics/GraphicsEngine/src/BufferBase.cpp b/Graphics/GraphicsEngine/src/BufferBase.cpp index aab770fd..5b72389a 100644 --- a/Graphics/GraphicsEngine/src/BufferBase.cpp +++ b/Graphics/GraphicsEngine/src/BufferBase.cpp @@ -45,7 +45,7 @@ namespace Diligent void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps) { - static_assert(BIND_FLAGS_LAST == 0x400L, "AZ TODO"); + static_assert(BIND_FLAGS_LAST == 0x400L, "Please update this function to handle the new bind flags"); constexpr Uint32 AllowedBindFlags = BIND_VERTEX_BUFFER | diff --git a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp index 6b613458..5e69da8e 100644 --- a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp @@ -41,6 +41,8 @@ #include "FramebufferD3D11Impl.hpp" #include "RenderPassD3D11Impl.hpp" #include "DisjointQueryPool.hpp" +#include "BottomLevelASBase.hpp" +#include "TopLevelASBase.hpp" #ifdef DILIGENT_DEBUG # define VERIFY_CONTEXT_BINDINGS @@ -58,6 +60,8 @@ struct DeviceContextD3D11ImplTraits using QueryType = QueryD3D11Impl; using FramebufferType = FramebufferD3D11Impl; using RenderPassType = RenderPassD3D11Impl; + using BottomLevelASType = BottomLevelASBase; + using TopLevelASType = TopLevelASBase; }; /// Device context implementation in Direct3D11 backend. diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index 9286f3f8..e42dd2d0 100755 --- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp @@ -2157,7 +2157,6 @@ void DeviceContextD3D11Impl::TransitionResourceStates(Uint32 BarrierCount, State #ifdef DILIGENT_DEVELOPMENT DvpVerifyStateTransitionDesc(Barrier); #endif - DEV_CHECK_ERR((Barrier.pTexture != nullptr) ^ (Barrier.pBuffer != nullptr), "Exactly one of pTexture or pBuffer must not be null"); DEV_CHECK_ERR(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "New resource state can't be unknown"); if (Barrier.TransitionType == STATE_TRANSITION_TYPE_BEGIN) @@ -2168,28 +2167,28 @@ void DeviceContextD3D11Impl::TransitionResourceStates(Uint32 BarrierCount, State } VERIFY(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END, "Unexpected barrier type"); - if (Barrier.pTexture) + RefCntAutoPtr pTexture{Barrier.pResource, IID_TextureD3D11}; + if (pTexture) { - auto* pTextureD3D11Impl = ValidatedCast(Barrier.pTexture); - auto OldState = Barrier.OldState; + auto OldState = Barrier.OldState; if (OldState == RESOURCE_STATE_UNKNOWN) { - if (pTextureD3D11Impl->IsInKnownState()) + if (pTexture->IsInKnownState()) { - OldState = pTextureD3D11Impl->GetState(); + OldState = pTexture->GetState(); } else { - LOG_ERROR_MESSAGE("Failed to transition the state of texture '", pTextureD3D11Impl->GetDesc().Name, "' because the buffer state is unknown and is not explicitly specified"); + LOG_ERROR_MESSAGE("Failed to transition the state of texture '", pTexture->GetDesc().Name, "' because the buffer state is unknown and is not explicitly specified"); continue; } } else { - if (pTextureD3D11Impl->IsInKnownState() && pTextureD3D11Impl->GetState() != OldState) + if (pTexture->IsInKnownState() && pTexture->GetState() != OldState) { - LOG_ERROR_MESSAGE("The state ", GetResourceStateString(pTextureD3D11Impl->GetState()), " of texture '", - pTextureD3D11Impl->GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(pTexture->GetState()), " of texture '", + pTexture->GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), " specified by the barrier"); } } @@ -2197,52 +2196,53 @@ void DeviceContextD3D11Impl::TransitionResourceStates(Uint32 BarrierCount, State if ((Barrier.NewState & RESOURCE_STATE_UNORDERED_ACCESS) != 0) { DEV_CHECK_ERR((Barrier.NewState & (RESOURCE_STATE_GENERIC_READ | RESOURCE_STATE_INPUT_ATTACHMENT)) == 0, "Unordered access state is not compatible with any input state"); - UnbindTextureFromInput(pTextureD3D11Impl, pTextureD3D11Impl->GetD3D11Texture()); + UnbindTextureFromInput(pTexture, pTexture->GetD3D11Texture()); } if ((Barrier.NewState & (RESOURCE_STATE_GENERIC_READ | RESOURCE_STATE_INPUT_ATTACHMENT)) != 0) { if ((OldState & RESOURCE_STATE_RENDER_TARGET) != 0) - UnbindTextureFromRenderTarget(pTextureD3D11Impl); + UnbindTextureFromRenderTarget(pTexture); if ((OldState & RESOURCE_STATE_DEPTH_WRITE) != 0) - UnbindTextureFromDepthStencil(pTextureD3D11Impl); + UnbindTextureFromDepthStencil(pTexture); if ((OldState & RESOURCE_STATE_UNORDERED_ACCESS) != 0) { - UnbindResourceFromUAV(pTextureD3D11Impl, pTextureD3D11Impl->GetD3D11Texture()); - pTextureD3D11Impl->ClearState(RESOURCE_STATE_UNORDERED_ACCESS); + UnbindResourceFromUAV(pTexture, pTexture->GetD3D11Texture()); + pTexture->ClearState(RESOURCE_STATE_UNORDERED_ACCESS); } } if (Barrier.UpdateResourceState) { - pTextureD3D11Impl->SetState(Barrier.NewState); + pTexture->SetState(Barrier.NewState); } + continue; } - else + + RefCntAutoPtr pBuffer{Barrier.pResource, IID_BufferD3D11}; + if (pBuffer) { - VERIFY_EXPR(Barrier.pBuffer); - auto* pBufferD3D11Impl = ValidatedCast(Barrier.pBuffer); - auto OldState = Barrier.OldState; + auto OldState = Barrier.OldState; if (OldState == RESOURCE_STATE_UNKNOWN) { - if (pBufferD3D11Impl->IsInKnownState()) + if (pBuffer->IsInKnownState()) { - OldState = pBufferD3D11Impl->GetState(); + OldState = pBuffer->GetState(); } else { - LOG_ERROR_MESSAGE("Failed to transition the state of buffer '", pBufferD3D11Impl->GetDesc().Name, "' because the buffer state is unknown and is not explicitly specified"); + LOG_ERROR_MESSAGE("Failed to transition the state of buffer '", pBuffer->GetDesc().Name, "' because the buffer state is unknown and is not explicitly specified"); continue; } } else { - if (pBufferD3D11Impl->IsInKnownState() && pBufferD3D11Impl->GetState() != OldState) + if (pBuffer->IsInKnownState() && pBuffer->GetState() != OldState) { - LOG_ERROR_MESSAGE("The state ", GetResourceStateString(pBufferD3D11Impl->GetState()), " of buffer '", - pBufferD3D11Impl->GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(pBuffer->GetState()), " of buffer '", + pBuffer->GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), " specified by the barrier"); } } @@ -2250,19 +2250,22 @@ void DeviceContextD3D11Impl::TransitionResourceStates(Uint32 BarrierCount, State if ((Barrier.NewState & RESOURCE_STATE_UNORDERED_ACCESS) != 0) { DEV_CHECK_ERR((Barrier.NewState & RESOURCE_STATE_GENERIC_READ) == 0, "Unordered access state is not compatible with any input state"); - UnbindBufferFromInput(pBufferD3D11Impl, pBufferD3D11Impl->m_pd3d11Buffer); + UnbindBufferFromInput(pBuffer, pBuffer->m_pd3d11Buffer); } if ((Barrier.NewState & RESOURCE_STATE_GENERIC_READ) != 0) { - UnbindResourceFromUAV(pBufferD3D11Impl, pBufferD3D11Impl->m_pd3d11Buffer); + UnbindResourceFromUAV(pBuffer, pBuffer->m_pd3d11Buffer); } if (Barrier.UpdateResourceState) { - pBufferD3D11Impl->SetState(Barrier.NewState); + pBuffer->SetState(Barrier.NewState); } + continue; } + + UNEXPECTED("unsupported resource type"); } } diff --git a/Graphics/GraphicsEngineD3D12/CMakeLists.txt b/Graphics/GraphicsEngineD3D12/CMakeLists.txt index 9941b62b..611bcbda 100644 --- a/Graphics/GraphicsEngineD3D12/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3D12/CMakeLists.txt @@ -37,6 +37,9 @@ set(INCLUDE include/SwapChainD3D12Impl.hpp include/TextureD3D12Impl.hpp include/TextureViewD3D12Impl.hpp + include/BottomLevelASD3D12Impl.hpp + include/TopLevelASD3D12Impl.hpp + include/ShaderBindingTableD3D12Impl.hpp ) set(INTERFACE @@ -55,6 +58,9 @@ set(INTERFACE interface/SwapChainD3D12.h interface/TextureD3D12.h interface/TextureViewD3D12.h + interface/BottomLevelASD3D12.h + interface/TopLevelASD3D12.h + interface/ShaderBindingTableD3D12.h ) @@ -89,6 +95,9 @@ set(SRC src/SwapChainD3D12Impl.cpp src/TextureD3D12Impl.cpp src/TextureViewD3D12Impl.cpp + src/BottomLevelASD3D12Impl.cpp + src/TopLevelASD3D12Impl.cpp + src/ShaderBindingTableD3D12Impl.cpp ) if(PLATFORM_WIN32) diff --git a/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp new file mode 100644 index 00000000..b631bdcc --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp @@ -0,0 +1,74 @@ +/* + * 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 +/// Declaration of Diligent::BottomLevelASD3D12Impl class + +#include "BottomLevelASD3D12.h" +#include "RenderDeviceD3D12.h" +#include "BottomLevelASBase.hpp" +#include "D3D12ResourceBase.hpp" +#include "RenderDeviceD3D12Impl.hpp" + +namespace Diligent +{ + +/// Bottom-level acceleration structure object implementation in Direct3D12 backend. +class BottomLevelASD3D12Impl final : public BottomLevelASBase, public D3D12ResourceBase +{ +public: + using TBottomLevelASBase = BottomLevelASBase; + + BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const BottomLevelASDesc& Desc, + bool bIsDeviceInternal = false); + ~BottomLevelASD3D12Impl(); + + virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; + + /// Implementation of IBottomLevelAS::GetScratchBufferSizes() in DirectX 12 backend. + virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override { return m_ScratchSize; } + + /// Implementation of IBottomLevelASD3D12::GetD3D12BLAS(). + virtual ID3D12Resource* DILIGENT_CALL_TYPE GetD3D12BLAS() override final { return GetD3D12Resource(); } + + /// Implementation of IBottomLevelAS::GetNativeHandle() in Direct3D12 backend. + virtual void* DILIGENT_CALL_TYPE GetNativeHandle() override final { return GetD3D12BLAS(); } + + D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress() + { + return GetD3D12Resource()->GetGPUVirtualAddress(); + } + +private: + ScratchBufferSizes m_ScratchSize; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp index ab90dfe7..ad3027a8 100644 --- a/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp @@ -103,6 +103,12 @@ public: } } + __forceinline D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress() + { + VERIFY_EXPR(m_Desc.Usage != USAGE_DYNAMIC); + return GetD3D12Resource()->GetGPUVirtualAddress(); + } + D3D12_CPU_DESCRIPTOR_HANDLE GetCBVHandle() { return m_CBVDescriptorAllocation.GetCpuHandle(); } private: diff --git a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp index 94f74933..511f1a03 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp +++ b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp @@ -34,6 +34,8 @@ #include "TextureViewD3D12.h" #include "TextureD3D12.h" #include "BufferD3D12.h" +#include "BottomLevelASD3D12.h" +#include "TopLevelASD3D12.h" #include "DescriptorHeap.hpp" namespace Diligent @@ -114,6 +116,8 @@ public: void TransitionResource(ITextureD3D12* pTexture, RESOURCE_STATE NewState); void TransitionResource(IBufferD3D12* pBuffer, RESOURCE_STATE NewState); + void TransitionResource(IBottomLevelASD3D12* pBLAS, RESOURCE_STATE NewState); + void TransitionResource(ITopLevelASD3D12* pTLAS, RESOURCE_STATE NewState); void TransitionResource(const StateTransitionDesc& Barrier); //void BeginResourceTransition(GpuResource& Resource, D3D12_RESOURCE_STATES NewState, bool FlushImmediate = false); @@ -238,8 +242,25 @@ protected: Uint32 m_MaxInterfaceVer = 0; }; +class ComputeContext : public CommandContext +{ +public: + void SetComputeRootSignature(ID3D12RootSignature* pRootSig) + { + if (pRootSig != m_pCurComputeRootSignature) + { + m_pCommandList->SetComputeRootSignature(m_pCurComputeRootSignature = pRootSig); + } + } -class GraphicsContext : public CommandContext + void Dispatch(size_t GroupCountX = 1, size_t GroupCountY = 1, size_t GroupCountZ = 1) + { + FlushResourceBarriers(); + m_pCommandList->Dispatch((UINT)GroupCountX, (UINT)GroupCountY, (UINT)GroupCountZ); + } +}; + +class GraphicsContext : public ComputeContext { public: void ClearRenderTarget(D3D12_CPU_DESCRIPTOR_HANDLE RTV, const float* Color) @@ -254,7 +275,7 @@ public: m_pCommandList->ClearDepthStencilView(DSV, ClearFlags, Depth, Stencil, 0, nullptr); } - void SetRootSignature(ID3D12RootSignature* pRootSig) + void SetGraphicsRootSignature(ID3D12RootSignature* pRootSig) { if (pRootSig != m_pCurGraphicsRootSignature) { @@ -291,47 +312,6 @@ public: } } - void SetConstants(UINT RootIndex, UINT NumConstants, const void* pConstants) - { - m_pCommandList->SetGraphicsRoot32BitConstants(RootIndex, NumConstants, pConstants, 0); - } - - void SetConstants(UINT RootIndex, DWParam X) - { - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, X.Uint, 0); - } - - void SetConstants(UINT RootIndex, DWParam X, DWParam Y) - { - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Y.Uint, 1); - } - - void SetConstants(UINT RootIndex, DWParam X, DWParam Y, DWParam Z) - { - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Y.Uint, 1); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Z.Uint, 2); - } - - void SetConstants(UINT RootIndex, DWParam X, DWParam Y, DWParam Z, DWParam W) - { - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Y.Uint, 1); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Z.Uint, 2); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, W.Uint, 3); - } - - void SetConstantBuffer(UINT RootIndex, D3D12_GPU_VIRTUAL_ADDRESS CBV) - { - m_pCommandList->SetGraphicsRootConstantBufferView(RootIndex, CBV); - } - - void SetDescriptorTable(UINT RootIndex, D3D12_GPU_DESCRIPTOR_HANDLE FirstHandle) - { - m_pCommandList->SetGraphicsRootDescriptorTable(RootIndex, FirstHandle); - } - void SetIndexBuffer(const D3D12_INDEX_BUFFER_VIEW& IBView) { m_pCommandList->IASetIndexBuffer(&IBView); @@ -384,83 +364,62 @@ public: { static_cast(m_pCommandList.p)->EndRenderPass(); } -}; -class GraphicsContext5 : public GraphicsContext4 -{ -}; - -class GraphicsContext6 : public GraphicsContext5 -{ -public: - void DrawMesh(UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) + void SetRayTracingPipelineState(ID3D12StateObject* pPSO) { -#ifdef D3D12_H_HAS_MESH_SHADER - FlushResourceBarriers(); - static_cast(m_pCommandList.p)->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); -#else - UNSUPPORTED("DrawMesh is not supported in current D3D12 header"); -#endif - } -}; - -class ComputeContext : public CommandContext -{ -public: - void SetRootSignature(ID3D12RootSignature* pRootSig) - { - if (pRootSig != m_pCurComputeRootSignature) + if (pPSO != m_pCurPipelineState) { - m_pCommandList->SetComputeRootSignature(m_pCurComputeRootSignature = pRootSig); + static_cast(m_pCommandList.p)->SetPipelineState1(pPSO); + m_pCurPipelineState = pPSO; } } - void SetConstants(UINT RootIndex, UINT NumConstants, const void* pConstants) - { - m_pCommandList->SetComputeRoot32BitConstants(RootIndex, NumConstants, pConstants, 0); - } - - void SetConstants(UINT RootIndex, DWParam X) - { - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, X.Uint, 0); - } - - void SetConstants(UINT RootIndex, DWParam X, DWParam Y) + void BuildRaytracingAccelerationStructure(const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC& Desc, + UINT NumPostbuildInfoDescs, + const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC* pPostbuildInfoDescs) { - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Y.Uint, 1); + FlushResourceBarriers(); + static_cast(m_pCommandList.p)->BuildRaytracingAccelerationStructure(&Desc, NumPostbuildInfoDescs, pPostbuildInfoDescs); } - void SetConstants(UINT RootIndex, DWParam X, DWParam Y, DWParam Z) + void EmitRaytracingAccelerationStructurePostbuildInfo(const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC& Desc, + UINT NumSourceAccelerationStructures, + const D3D12_GPU_VIRTUAL_ADDRESS* pSourceAccelerationStructureData) { - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Y.Uint, 1); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Z.Uint, 2); + FlushResourceBarriers(); + static_cast(m_pCommandList.p)->EmitRaytracingAccelerationStructurePostbuildInfo(&Desc, NumSourceAccelerationStructures, pSourceAccelerationStructureData); } - void SetConstants(UINT RootIndex, DWParam X, DWParam Y, DWParam Z, DWParam W) + void CopyRaytracingAccelerationStructure(D3D12_GPU_VIRTUAL_ADDRESS DestAccelerationStructureData, + D3D12_GPU_VIRTUAL_ADDRESS SourceAccelerationStructureData, + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE Mode) { - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Y.Uint, 1); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Z.Uint, 2); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, W.Uint, 3); + FlushResourceBarriers(); + static_cast(m_pCommandList.p)->CopyRaytracingAccelerationStructure(DestAccelerationStructureData, SourceAccelerationStructureData, Mode); } - - void SetConstantBuffer(UINT RootIndex, D3D12_GPU_VIRTUAL_ADDRESS CBV) + void DispatchRays(const D3D12_DISPATCH_RAYS_DESC& Desc) { - m_pCommandList->SetComputeRootConstantBufferView(RootIndex, CBV); + FlushResourceBarriers(); + static_cast(m_pCommandList.p)->DispatchRays(&Desc); } +}; - void SetDescriptorTable(UINT RootIndex, D3D12_GPU_DESCRIPTOR_HANDLE FirstHandle) - { - m_pCommandList->SetComputeRootDescriptorTable(RootIndex, FirstHandle); - } +class GraphicsContext5 : public GraphicsContext4 +{ +}; - void Dispatch(size_t GroupCountX = 1, size_t GroupCountY = 1, size_t GroupCountZ = 1) +class GraphicsContext6 : public GraphicsContext5 +{ +public: + void DrawMesh(UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) { +#ifdef D3D12_H_HAS_MESH_SHADER FlushResourceBarriers(); - m_pCommandList->Dispatch((UINT)GroupCountX, (UINT)GroupCountY, (UINT)GroupCountZ); + static_cast(m_pCommandList.p)->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); +#else + UNSUPPORTED("DrawMesh is not supported in current D3D12 header"); +#endif } }; diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.hpp b/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.hpp index 240ea165..e3a78c6c 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.hpp +++ b/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.hpp @@ -43,7 +43,7 @@ public: ID3D12Resource* GetD3D12Resource() { return m_pd3d12Resource; } protected: - CComPtr m_pd3d12Resource; ///< D3D12 buffer object + CComPtr m_pd3d12Resource; ///< D3D12 resource object }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp index c6678ddd..389b76a1 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp +++ b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp @@ -78,5 +78,9 @@ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE AttachmentStoreOpToD3D12EndingAccessType D3D12_SHADER_VISIBILITY ShaderTypeToD3D12ShaderVisibility(SHADER_TYPE ShaderType); SHADER_TYPE D3D12ShaderVisibilityToShaderType(D3D12_SHADER_VISIBILITY ShaderVisibility); +DXGI_FORMAT ValueTypeToIndexType(VALUE_TYPE Type); + +D3D12_RAYTRACING_GEOMETRY_FLAGS GeometryFlagsToD3D12RTGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flags); +D3D12_RAYTRACING_INSTANCE_FLAGS InstanceFlagsToD3D12RTInstanceFlags(RAYTRACING_INSTANCE_FLAGS Flags); } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp index 39a354dd..3ac65274 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp @@ -42,6 +42,8 @@ #include "RenderPassD3D12Impl.hpp" #include "PipelineStateD3D12Impl.hpp" #include "D3D12DynamicHeap.hpp" +#include "BottomLevelASD3D12Impl.hpp" +#include "TopLevelASD3D12Impl.hpp" namespace Diligent { @@ -56,6 +58,8 @@ struct DeviceContextD3D12ImplTraits using QueryType = QueryD3D12Impl; using FramebufferType = FramebufferD3D12Impl; using RenderPassType = RenderPassD3D12Impl; + using BottomLevelASType = BottomLevelASD3D12Impl; + using TopLevelASType = TopLevelASD3D12Impl; }; /// Device context implementation in Direct3D12 backend. @@ -125,13 +129,13 @@ public: ITextureView* pDepthStencil, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) override final; - /// Implementation of IDeviceContext::BeginRenderPass() in Direct3D11 backend. + /// Implementation of IDeviceContext::BeginRenderPass() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE BeginRenderPass(const BeginRenderPassAttribs& Attribs) override final; - /// Implementation of IDeviceContext::NextSubpass() in Direct3D11 backend. + /// Implementation of IDeviceContext::NextSubpass() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE NextSubpass() override final; - /// Implementation of IDeviceContext::EndRenderPass() in Direct3D11 backend. + /// Implementation of IDeviceContext::EndRenderPass() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE EndRenderPass() override final; // clang-format off @@ -351,12 +355,23 @@ private: RESOURCE_STATE_TRANSITION_MODE TransitionMode, RESOURCE_STATE RequiredState, const char* OperationName); + __forceinline void TransitionOrVerifyBLASState(CommandContext& CmdCtx, + BottomLevelASD3D12Impl& BLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName); + __forceinline void TransitionOrVerifyTLASState(CommandContext& CmdCtx, + TopLevelASD3D12Impl& TLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName); __forceinline void PrepareForDraw(GraphicsContext& GraphCtx, DRAW_FLAGS Flags); __forceinline void PrepareForIndexedDraw(GraphicsContext& GraphCtx, DRAW_FLAGS Flags, VALUE_TYPE IndexType); __forceinline void PrepareForDispatchCompute(ComputeContext& GraphCtx); + __forceinline void PrepareForDispatchRays(GraphicsContext& GraphCtx); __forceinline void PrepareDrawIndirectBuffer(GraphicsContext& GraphCtx, IBuffer* pAttribsBuffer, diff --git a/Graphics/GraphicsEngineD3D12/include/FramebufferD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/FramebufferD3D12Impl.hpp index 59642660..31b65866 100644 --- a/Graphics/GraphicsEngineD3D12/include/FramebufferD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/FramebufferD3D12Impl.hpp @@ -39,7 +39,7 @@ namespace Diligent class FixedBlockMemoryAllocator; -/// Render pass implementation in Direct3D11 backend. +/// Render pass implementation in Direct3D12 backend. class FramebufferD3D12Impl final : public FramebufferBase { public: diff --git a/Graphics/GraphicsEngineD3D12/include/RenderPassD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderPassD3D12Impl.hpp index 501e62df..00984731 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderPassD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderPassD3D12Impl.hpp @@ -39,7 +39,7 @@ namespace Diligent class FixedBlockMemoryAllocator; -/// Render pass implementation in Direct3D11 backend. +/// Render pass implementation in Direct3D12 backend. class RenderPassD3D12Impl final : public RenderPassBase { public: diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp new file mode 100644 index 00000000..e866c6f2 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp @@ -0,0 +1,79 @@ +/* + * 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 +/// Declaration of Diligent::ShaderBindingTableD3D12Impl class + +#include "ShaderBindingTableD3D12.h" +#include "RenderDeviceD3D12.h" +#include "ShaderBindingTableBase.hpp" +#include "D3D12ResourceBase.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "PipelineStateD3D12Impl.hpp" + +namespace Diligent +{ + +/// Shader binding table object implementation in Direct3D12 backend. +class ShaderBindingTableD3D12Impl final : public ShaderBindingTableBase, public D3D12ResourceBase +{ +public: + using TShaderBindingTableBase = ShaderBindingTableBase; + + ShaderBindingTableD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const ShaderBindingTableDesc& Desc, + bool bIsDeviceInternal = false); + ~ShaderBindingTableD3D12Impl(); + + virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; + + virtual void DILIGENT_CALL_TYPE Verify() const override; + + virtual void DILIGENT_CALL_TYPE Reset(const ShaderBindingTableDesc& Desc) override; + + virtual void DILIGENT_CALL_TYPE ResetHitGroups(Uint32 HitShadersPerInstance) override; + + virtual void DILIGENT_CALL_TYPE BindAll(const BindAllAttribs& Attribs) override; + + virtual void DILIGENT_CALL_TYPE GetD3D12AddressRangeAndStride(IDeviceContextD3D12* pContext, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE& RaygenShaderBindingTable, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE& MissShaderBindingTable, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE& HitShaderBindingTable, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE& CallableShaderBindingTable) override; + +private: + void ValidateDesc(const ShaderBindingTableDesc& Desc) const; + +private: + RefCntAutoPtr m_pBuffer; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp new file mode 100644 index 00000000..8eccf530 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp @@ -0,0 +1,83 @@ +/* + * 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 +/// Declaration of Diligent::TopLevelASD3D12Impl class + +#include "TopLevelASD3D12.h" +#include "RenderDeviceD3D12.h" +#include "TopLevelASBase.hpp" +#include "D3D12ResourceBase.hpp" +#include "RenderDeviceD3D12Impl.hpp" + +namespace Diligent +{ + +/// Top-level acceleration structure object implementation in Direct3D12 backend. +class TopLevelASD3D12Impl final : public TopLevelASBase, public D3D12ResourceBase +{ +public: + using TTopLevelASBase = TopLevelASBase; + + TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const TopLevelASDesc& Desc, + bool bIsDeviceInternal = false); + ~TopLevelASD3D12Impl(); + + virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; + + /// Implementation of ITopLevelASD3D12::GetScratchBufferSizes() in DirectX 12 backend. + virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override { return m_ScratchSize; } + + /// Implementation of ITopLevelASD3D12D3D12::GetD3D12TLAS(). + virtual ID3D12Resource* DILIGENT_CALL_TYPE GetD3D12TLAS() override final { return GetD3D12Resource(); } + + /// Implementation of ITopLevelASD3D12::GetNativeHandle() in Direct3D12 backend. + virtual void* DILIGENT_CALL_TYPE GetNativeHandle() override final { return GetD3D12TLAS(); } + + D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress() + { + return GetD3D12Resource()->GetGPUVirtualAddress(); + } + + /// Implementation of ITopLevelASD3D12::GetCPUDescriptorHandle() in Direct3D12 backend. + virtual D3D12_CPU_DESCRIPTOR_HANDLE DILIGENT_CALL_TYPE GetCPUDescriptorHandle() override final + { + return m_DescriptorHandle.GetCpuHandle(); + } + +private: + ScratchBufferSizes m_ScratchSize; + + // Allocation in a CPU-only descriptor heap + DescriptorHeapAllocation m_DescriptorHandle; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/interface/BottomLevelASD3D12.h b/Graphics/GraphicsEngineD3D12/interface/BottomLevelASD3D12.h new file mode 100644 index 00000000..2b64da57 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/interface/BottomLevelASD3D12.h @@ -0,0 +1,70 @@ +/* + * 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 +/// Definition of the Diligent::IBottomLevelASD3D12 interface + +#include "../../GraphicsEngine/interface/BottomLevelAS.h" +#include "../../GraphicsEngine/interface/DeviceContext.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {610228AF-F161-4B12-A00E-71E6E3BB97FE} +static const INTERFACE_ID IID_BottomLevelASD3D12 = + {0x610228af, 0xf161, 0x4b12, {0xa0, 0xe, 0x71, 0xe6, 0xe3, 0xbb, 0x97, 0xfe}}; + +#define DILIGENT_INTERFACE_NAME IBottomLevelASD3D12 +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define IBottomLevelASD3D12InclusiveMethods \ + IBottomLevelASInclusiveMethods; \ + IBottomLevelASD3D12Methods BottomLevelASD3D12 + +// clang-format off + +/// Exposes Direct3D12-specific functionality of a bottom-level acceleration structure object. +DILIGENT_BEGIN_INTERFACE(IBottomLevelASD3D12, IBottomLevelAS) +{ + /// Returns ID3D12Resource interface of the internal D3D12 acceleration structure object. + + /// The method does *NOT* call AddRef() on the returned interface, + /// so Release() must not be called. + VIRTUAL ID3D12Resource* METHOD(GetD3D12BLAS)(THIS) PURE; +}; +DILIGENT_END_INTERFACE + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +# define IBottomLevelASD3D12_GetD3D12BLAS(This) CALL_IFACE_METHOD(IBottomLevelASD3D12, GetD3D12BLAS, This) + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h b/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h new file mode 100644 index 00000000..f33bac1b --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h @@ -0,0 +1,71 @@ +/* + * 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 +/// Definition of the Diligent::IShaderBindingTableD3D12 interface + +#include "../../GraphicsEngine/interface/ShaderBindingTable.h" +#include "DeviceContextD3D12.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {DCA2FAD9-2C41-4419-9D16-79731C0ED9D8} +static const INTERFACE_ID IID_ShaderBindingTableD3D12 = + {0xdca2fad9, 0x2c41, 0x4419, {0x9d, 0x16, 0x79, 0x73, 0x1c, 0xe, 0xd9, 0xd8}}; + +#define DILIGENT_INTERFACE_NAME IShaderBindingTableD3D12 +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define IShaderBindingTableD3D12InclusiveMethods \ + IShaderBindingTableInclusiveMethods; \ + IShaderBindingTableD3D12Methods ShaderBindingTable +// clang-format off + +/// Exposes Direct3D12-specific functionality of a shader binding table object. +DILIGENT_BEGIN_INTERFACE(IShaderBindingTableD3D12, IShaderBindingTable) +{ + /// AZ TODO + VIRTUAL void METHOD(GetD3D12AddressRangeAndStride)(THIS_ + IDeviceContextD3D12* pContext, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE REF RaygenShaderBindingTable, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE REF MissShaderBindingTable, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE REF HitShaderBindingTable, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE REF CallableShaderBindingTable) PURE; +}; +DILIGENT_END_INTERFACE + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/interface/TopLevelASD3D12.h b/Graphics/GraphicsEngineD3D12/interface/TopLevelASD3D12.h new file mode 100644 index 00000000..5b2bd512 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/interface/TopLevelASD3D12.h @@ -0,0 +1,77 @@ +/* + * 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 +/// Definition of the Diligent::ITopLevelASD3D12 interface + +#include "../../GraphicsEngine/interface/TopLevelAS.h" +#include "../../GraphicsEngine/interface/DeviceContext.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {46334F12-64CB-4F7C-BB71-31515B6F386D} +static const INTERFACE_ID IID_TopLevelASD3D12 = + {0x46334f12, 0x64cb, 0x4f7c, {0xbb, 0x71, 0x31, 0x51, 0x5b, 0x6f, 0x38, 0x6d}}; + +#define DILIGENT_INTERFACE_NAME ITopLevelASD3D12 +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define ITopLevelASD3D12InclusiveMethods \ + ITopLevelASInclusiveMethods; \ + ITopLevelASD3D12Methods TopLevelASD3D12 + +// clang-format off + +/// Exposes Direct3D12-specific functionality of a top-level acceleration structure object. +DILIGENT_BEGIN_INTERFACE(ITopLevelASD3D12, ITopLevelAS) +{ + /// Returns ID3D12Resource interface of the internal D3D12 acceleration structure object. + + /// The method does *NOT* call AddRef() on the returned interface, + /// so Release() must not be called. + VIRTUAL ID3D12Resource* METHOD(GetD3D12TLAS)(THIS) PURE; + + /// Returns a CPU descriptor handle of the D3D12 acceleration structure + + /// The method does *NOT* call AddRef() on the returned interface, + /// so Release() must not be called. + VIRTUAL D3D12_CPU_DESCRIPTOR_HANDLE METHOD(GetCPUDescriptorHandle)(THIS) PURE; +}; +DILIGENT_END_INTERFACE + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +# define ITopLevelASD3D12_GetD3D12TLAS(This) CALL_IFACE_METHOD(ITopLevelASD3D12, GetD3D12TLAS, This) +# define ITopLevelASD3D12_GetCPUDescriptorHandle(This) CALL_IFACE_METHOD(ITopLevelASD3D12, GetCPUDescriptorHandle, This) + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp new file mode 100644 index 00000000..31f0e6a3 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#include "pch.h" +#include "BottomLevelASD3D12Impl.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "DeviceContextD3D12Impl.hpp" +#include "D3D12TypeConversions.hpp" +#include "GraphicsAccessories.hpp" +#include "DXGITypeConversions.hpp" +#include "EngineMemory.h" +#include "StringTools.hpp" + +namespace Diligent +{ + +BottomLevelASD3D12Impl::BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const BottomLevelASDesc& Desc, + bool bIsDeviceInternal) : + TBottomLevelASBase{pRefCounters, pDeviceD3D12, Desc, bIsDeviceInternal} +{ + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO BottomLevelPrebuildInfo = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS BottomLevelInputs = {}; + std::vector Geometries; + + if (m_Desc.pTriangles != nullptr) + { + Geometries.resize(m_Desc.TriangleCount); + Uint32 MaxPrimitiveCount = 0; + for (uint32_t i = 0; i < m_Desc.TriangleCount; ++i) + { + auto& src = m_Desc.pTriangles[i]; + auto& dst = Geometries[i]; + + dst.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + dst.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; + dst.Triangles.VertexBuffer.StartAddress = 0; + dst.Triangles.VertexBuffer.StrideInBytes = 0; + dst.Triangles.VertexFormat = TypeToDXGI_Format(src.VertexValueType, src.VertexComponentCount, src.VertexValueType < VT_FLOAT16); + dst.Triangles.VertexCount = src.MaxVertexCount; + dst.Triangles.IndexCount = src.MaxIndexCount; + dst.Triangles.IndexFormat = ValueTypeToIndexType(src.IndexType); + dst.Triangles.IndexBuffer = 0; + dst.Triangles.Transform3x4 = 0; + + MaxPrimitiveCount += src.MaxIndexCount ? src.MaxIndexCount / 3 : src.MaxVertexCount / 3; + } + VERIFY_EXPR(MaxPrimitiveCount <= D3D12_RAYTRACING_MAX_PRIMITIVES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE); + } + else if (m_Desc.pBoxes != nullptr) + { + Geometries.resize(m_Desc.BoxCount); + Uint32 MaxBoxCount = 0; + for (uint32_t i = 0; i < m_Desc.BoxCount; ++i) + { + auto& src = m_Desc.pBoxes[i]; + auto& dst = Geometries[i]; + + dst.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + dst.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; + dst.AABBs.AABBCount = src.MaxBoxCount; + dst.AABBs.AABBs.StartAddress = 0; + dst.AABBs.AABBs.StrideInBytes = 0; + + MaxBoxCount += src.MaxBoxCount; + } + VERIFY_EXPR(MaxBoxCount <= D3D12_RAYTRACING_MAX_PRIMITIVES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE); + } + + VERIFY_EXPR(Geometries.size() <= D3D12_RAYTRACING_MAX_GEOMETRIES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE); + + BottomLevelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + BottomLevelInputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE; + BottomLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + BottomLevelInputs.pGeometryDescs = Geometries.data(); + BottomLevelInputs.NumDescs = static_cast(Geometries.size()); + + auto* pd3d12Device = pDeviceD3D12->GetD3D12Device5(); + + pd3d12Device->GetRaytracingAccelerationStructurePrebuildInfo(&BottomLevelInputs, &BottomLevelPrebuildInfo); + if (BottomLevelPrebuildInfo.ResultDataMaxSizeInBytes == 0) + LOG_ERROR_AND_THROW("Failed to get ray tracing acceleration structure prebuild info"); + + D3D12_HEAP_PROPERTIES HeapProps; + HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + HeapProps.CreationNodeMask = 1; + HeapProps.VisibleNodeMask = 1; + + D3D12_RESOURCE_DESC ASDesc = {}; + ASDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + ASDesc.Alignment = 0; + ASDesc.Width = BottomLevelPrebuildInfo.ResultDataMaxSizeInBytes; + ASDesc.Height = 1; + ASDesc.DepthOrArraySize = 1; + ASDesc.MipLevels = 1; + ASDesc.Format = DXGI_FORMAT_UNKNOWN; + ASDesc.SampleDesc.Count = 1; + ASDesc.SampleDesc.Quality = 0; + ASDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + ASDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + auto hr = pd3d12Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, + &ASDesc, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, nullptr, + __uuidof(m_pd3d12Resource), + reinterpret_cast(static_cast(&m_pd3d12Resource))); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create D3D12 Bottom-level acceleration structure"); + + if (*m_Desc.Name != 0) + m_pd3d12Resource->SetName(WidenString(m_Desc.Name).c_str()); + + m_ScratchSize.Build = static_cast(BottomLevelPrebuildInfo.ScratchDataSizeInBytes); + m_ScratchSize.Update = static_cast(BottomLevelPrebuildInfo.UpdateScratchDataSizeInBytes); +} + +BottomLevelASD3D12Impl::~BottomLevelASD3D12Impl() +{ + // D3D12 object can only be destroyed when it is no longer used by the GPU + auto* pDeviceD3D12Impl = ValidatedCast(GetDevice()); + pDeviceD3D12Impl->SafeReleaseDeviceObject(std::move(m_pd3d12Resource), m_Desc.CommandQueueMask); +} + +IMPLEMENT_QUERY_INTERFACE(BottomLevelASD3D12Impl, IID_BottomLevelASD3D12, TBottomLevelASBase) + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp index d7cd54b6..8e84b844 100644 --- a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp @@ -118,9 +118,9 @@ BufferD3D12Impl::BufferD3D12Impl(IReferenceCounters* pRefCounters, // understood by applications and row-major texture data is commonly marshaled through buffers. D3D12BuffDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; D3D12BuffDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS) + if ((m_Desc.BindFlags & BIND_UNORDERED_ACCESS) || (m_Desc.BindFlags & BIND_RAY_TRACING)) D3D12BuffDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - if (!(m_Desc.BindFlags & BIND_SHADER_RESOURCE)) + if (!(m_Desc.BindFlags & BIND_SHADER_RESOURCE) && !(m_Desc.BindFlags & BIND_RAY_TRACING)) D3D12BuffDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; auto* pd3d12Device = pRenderDeviceD3D12->GetD3D12Device(); diff --git a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp index 389bf3eb..6bc55ac3 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp @@ -30,6 +30,8 @@ #include "CommandContext.hpp" #include "TextureD3D12Impl.hpp" #include "BufferD3D12Impl.hpp" +#include "BottomLevelASD3D12Impl.hpp" +#include "TopLevelASD3D12Impl.hpp" #include "CommandListManager.hpp" #include "D3D12TypeConversions.hpp" @@ -39,9 +41,9 @@ namespace Diligent CommandContext::CommandContext(CommandListManager& CmdListManager) : // clang-format off - m_pCurGraphicsRootSignature {nullptr}, - m_pCurPipelineState {nullptr}, - m_pCurComputeRootSignature {nullptr}, + m_pCurGraphicsRootSignature {nullptr}, + m_pCurPipelineState {nullptr}, + m_pCurComputeRootSignature {nullptr}, m_PendingResourceBarriers (STD_ALLOCATOR_RAW_MEM(D3D12_RESOURCE_BARRIER, GetRawAllocator(), "Allocator for vector")) // clang-format on { @@ -78,7 +80,7 @@ void CommandContext::Reset(CommandListManager& CmdListManager) m_PrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; #if 0 - BindDescriptorHeaps(); + BindDescriptorHeaps(); #endif } @@ -115,6 +117,24 @@ void CommandContext::TransitionResource(IBufferD3D12* pBuffer, RESOURCE_STATE Ne TransitionResource(BufferBarrier); } +void CommandContext::TransitionResource(IBottomLevelASD3D12* pBLAS, RESOURCE_STATE NewState) +{ + VERIFY_EXPR(pBLAS != nullptr); + auto* pBLASfD3D12 = ValidatedCast(pBLAS); + VERIFY(pBLASfD3D12->IsInKnownState(), "BLAS state can't be unknown"); + StateTransitionDesc ASBarrier(pBLAS, RESOURCE_STATE_UNKNOWN, NewState, true); + TransitionResource(ASBarrier); +} + +void CommandContext::TransitionResource(ITopLevelASD3D12* pTLAS, RESOURCE_STATE NewState) +{ + VERIFY_EXPR(pTLAS != nullptr); + auto* pTLASfD3D12 = ValidatedCast(pTLAS); + VERIFY(pTLASfD3D12->IsInKnownState(), "TLAS state can't be unknown"); + StateTransitionDesc ASBarrier(pTLAS, RESOURCE_STATE_UNKNOWN, NewState, true); + TransitionResource(ASBarrier); +} + void CommandContext::InsertUAVBarrier(ID3D12Resource* pd3d12Resource) { m_PendingResourceBarriers.emplace_back(); @@ -147,25 +167,23 @@ static D3D12_RESOURCE_BARRIER_FLAGS TransitionTypeToD3D12ResourceBarrierFlag(STA void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) { - DEV_CHECK_ERR((Barrier.pTexture != nullptr) ^ (Barrier.pBuffer != nullptr), "Exactly one of pTexture or pBuffer must not be null"); - DEV_CHECK_ERR(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "New resource state can't be unknown"); - RESOURCE_STATE OldState = RESOURCE_STATE_UNKNOWN; - ID3D12Resource* pd3d12Resource = nullptr; - TextureD3D12Impl* pTextureD3D12Impl = nullptr; - BufferD3D12Impl* pBufferD3D12Impl = nullptr; - if (Barrier.pTexture) + RESOURCE_STATE OldState = RESOURCE_STATE_UNKNOWN; + ID3D12Resource* pd3d12Resource = nullptr; + RefCntAutoPtr pTextureD3D12Impl{Barrier.pResource, IID_TextureD3D12}; + RefCntAutoPtr pBufferD3D12Impl{Barrier.pResource, IID_BufferD3D12}; + RefCntAutoPtr pBLASD3D12Impl{Barrier.pResource, IID_BottomLevelASD3D12}; + RefCntAutoPtr pTLASD3D12Impl{Barrier.pResource, IID_TopLevelASD3D12}; + + if (pTextureD3D12Impl) { - pTextureD3D12Impl = ValidatedCast(Barrier.pTexture); - pd3d12Resource = pTextureD3D12Impl->GetD3D12Resource(); - OldState = pTextureD3D12Impl->GetState(); + pd3d12Resource = pTextureD3D12Impl->GetD3D12Resource(); + OldState = pTextureD3D12Impl->GetState(); } - else + else if (pBufferD3D12Impl) { - VERIFY_EXPR(Barrier.pBuffer != nullptr); - pBufferD3D12Impl = ValidatedCast(Barrier.pBuffer); - pd3d12Resource = pBufferD3D12Impl->GetD3D12Resource(); - OldState = pBufferD3D12Impl->GetState(); + pd3d12Resource = pBufferD3D12Impl->GetD3D12Resource(); + OldState = pBufferD3D12Impl->GetState(); #ifdef DILIGENT_DEVELOPMENT // Dynamic buffers wtih no SRV/UAV bind flags are suballocated in @@ -178,6 +196,20 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) } #endif } + else if (pBLASD3D12Impl) + { + pd3d12Resource = pBLASD3D12Impl->GetD3D12Resource(); + OldState = pBLASD3D12Impl->GetState(); + } + else if (pTLASD3D12Impl) + { + pd3d12Resource = pTLASD3D12Impl->GetD3D12Resource(); + OldState = pTLASD3D12Impl->GetState(); + } + else + { + UNEXPECTED("unsupported resource type"); + } if (OldState == RESOURCE_STATE_UNKNOWN) { @@ -243,9 +275,8 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) } } } - else + else if (pBufferD3D12Impl) { - VERIFY_EXPR(pBufferD3D12Impl); m_PendingResourceBarriers.emplace_back(BarrierDesc); } } @@ -259,10 +290,8 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) pTextureD3D12Impl->SetState(NewState); } } - else + else if (pBufferD3D12Impl) { - VERIFY_EXPR(pBufferD3D12Impl); - VERIFY(!Barrier.UpdateResourceState || (Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END), "Buffer state can't be updated in begin-split barrier"); if (Barrier.UpdateResourceState) @@ -275,9 +304,29 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) "Dynamic buffers without SRV/UAV bind flag are expected to never " "transition from RESOURCE_STATE_GENERIC_READ state"); } + else if (pBLASD3D12Impl) + { + VERIFY(!Barrier.UpdateResourceState || (Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END), + "Bottom-level acceleration structure state can't be updated in begin-split barrier"); + if (Barrier.UpdateResourceState) + { + pBLASD3D12Impl->SetState(NewState); + } + } + else if (pTLASD3D12Impl) + { + VERIFY(!Barrier.UpdateResourceState || (Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END), + "Top-level acceleration structure state can't be updated in begin-split barrier"); + if (Barrier.UpdateResourceState) + { + pTLASD3D12Impl->SetState(NewState); + } + } } - if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS) + if ((OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS) || + (OldState == RESOURCE_STATE_BUILD_AS_WRITE && Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE) || + (OldState == RESOURCE_STATE_RAY_TRACING && Barrier.NewState == RESOURCE_STATE_RAY_TRACING)) { DEV_CHECK_ERR(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE, "UAV barriers must not be split"); InsertUAVBarrier(pd3d12Resource); diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp index 3ea4bad0..ddab5096 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp @@ -351,8 +351,9 @@ static D3D12_RESOURCE_STATES ResourceStateFlagToD3D12ResourceState(RESOURCE_STAT case RESOURCE_STATE_RESOLVE_SOURCE: return D3D12_RESOURCE_STATE_RESOLVE_SOURCE; case RESOURCE_STATE_INPUT_ATTACHMENT: return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; case RESOURCE_STATE_PRESENT: return D3D12_RESOURCE_STATE_PRESENT; - case RESOURCE_STATE_BUILD_AS: return D3D12_RESOURCE_STATES(0); - case RESOURCE_STATE_RAY_TRACING: return D3D12_RESOURCE_STATES(0); // AZ TODO + case RESOURCE_STATE_BUILD_AS_READ: return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + case RESOURCE_STATE_BUILD_AS_WRITE: return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + case RESOURCE_STATE_RAY_TRACING: return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; // clang-format on default: UNEXPECTED("Unexpected resource state flag"); @@ -379,7 +380,7 @@ public: } private: - static constexpr Uint32 MaxFlagBitPos = 18; + static constexpr Uint32 MaxFlagBitPos = 19; std::array FlagBitPosToResStateMap; }; @@ -422,7 +423,6 @@ static RESOURCE_STATE D3D12ResourceStateToResourceStateFlags(D3D12_RESOURCE_STAT case D3D12_RESOURCE_STATE_COPY_SOURCE: return RESOURCE_STATE_COPY_SOURCE; case D3D12_RESOURCE_STATE_RESOLVE_DEST: return RESOURCE_STATE_RESOLVE_DEST; case D3D12_RESOURCE_STATE_RESOLVE_SOURCE: return RESOURCE_STATE_RESOLVE_SOURCE; - // AZ TODO // clang-format on default: UNEXPECTED("Unexpected D3D12 resource state"); @@ -592,5 +592,67 @@ SHADER_TYPE D3D12ShaderVisibilityToShaderType(D3D12_SHADER_VISIBILITY ShaderVisi } } +DXGI_FORMAT ValueTypeToIndexType(VALUE_TYPE IndexType) +{ + switch (IndexType) + { + // clang-format off + case VT_UNDEFINED: return DXGI_FORMAT_UNKNOWN; // only for ray tracing + case VT_UINT16: return DXGI_FORMAT_R16_UINT; + case VT_UINT32: return DXGI_FORMAT_R32_UINT; + // clang-format on + default: + UNEXPECTED("Unexpected index type"); + return DXGI_FORMAT_R32_UINT; + } +} + +D3D12_RAYTRACING_GEOMETRY_FLAGS GeometryFlagsToD3D12RTGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flags) +{ + static_assert(RAYTRACING_GEOMETRY_FLAGS_LAST == RAYTRACING_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION, + "Please update the switch below to handle the new ray tracing geometry flag"); + + Uint32 Result = 0; + for (Uint32 Bit = 1; Bit <= Flags; Bit <<= 1) + { + if ((Flags & Bit) != Bit) + continue; + + switch (static_cast(Bit)) + { + // clang-format off + case RAYTRACING_GEOMETRY_OPAQUE: Result |= D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; break; + case RAYTRACING_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION: Result |= D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; break; + // clang-format on + default: UNEXPECTED("unknown geometry flag"); + } + } + return static_cast(Result); +} + +D3D12_RAYTRACING_INSTANCE_FLAGS InstanceFlagsToD3D12RTInstanceFlags(RAYTRACING_INSTANCE_FLAGS Flags) +{ + static_assert(RAYTRACING_INSTANCE_FLAGS_LAST == RAYTRACING_INSTANCE_FORCE_NO_OPAQUE, + "Please update the switch below to handle the new ray tracing instance flag"); + + Uint32 Result = 0; + for (Uint32 Bit = 1; Bit <= Flags; Bit <<= 1) + { + if ((Flags & Bit) != Bit) + continue; + + switch (static_cast(Bit)) + { + // clang-format off + case RAYTRACING_INSTANCE_TRIANGLE_FACING_CULL_DISABLE: Result |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_CULL_DISABLE ; break; + case RAYTRACING_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE: Result |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE ; break; + case RAYTRACING_INSTANCE_FORCE_OPAQUE: Result |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_OPAQUE ; break; + case RAYTRACING_INSTANCE_FORCE_NO_OPAQUE: Result |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_NON_OPAQUE ; break; + // clang-format on + default: UNEXPECTED("unknown instance flag"); + } + } + return static_cast(Result); +} } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 6ca74c27..95025c4c 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -39,6 +39,7 @@ #include "D3D12DynamicHeap.hpp" #include "CommandListD3D12Impl.hpp" #include "DXGITypeConversions.hpp" +#include "ShaderBindingTableD3D12Impl.hpp" namespace Diligent { @@ -262,6 +263,8 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) } case PIPELINE_TYPE_RAY_TRACING: { + auto* pd3d12SO = pPipelineStateD3D12->GetD3D12StateObject(); + CmdCtx.AsGraphicsContext4().SetRayTracingPipelineState(pd3d12SO); break; } default: @@ -449,7 +452,7 @@ void DeviceContextD3D12Impl::PrepareForDraw(GraphicsContext& GraphCtx, DRAW_FLAG } #endif - GraphCtx.SetRootSignature(m_pPipelineState->GetD3D12RootSignature()); + GraphCtx.SetGraphicsRootSignature(m_pPipelineState->GetD3D12RootSignature()); if (m_State.pCommittedResourceCache != nullptr) { @@ -605,7 +608,7 @@ void DeviceContextD3D12Impl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Att void DeviceContextD3D12Impl::PrepareForDispatchCompute(ComputeContext& ComputeCtx) { - ComputeCtx.SetRootSignature(m_pPipelineState->GetD3D12RootSignature()); + ComputeCtx.SetComputeRootSignature(m_pPipelineState->GetD3D12RootSignature()); if (m_State.pCommittedResourceCache != nullptr) { if (m_State.pCommittedResourceCache->GetNumDynamicCBsBound() > 0) @@ -634,6 +637,37 @@ void DeviceContextD3D12Impl::PrepareForDispatchCompute(ComputeContext& ComputeCt #endif } +void DeviceContextD3D12Impl::PrepareForDispatchRays(GraphicsContext& GraphCtx) +{ + GraphCtx.SetComputeRootSignature(m_pPipelineState->GetD3D12RootSignature()); + if (m_State.pCommittedResourceCache != nullptr) + { + if (m_State.pCommittedResourceCache->GetNumDynamicCBsBound() > 0) + { + // Only process dynamic buffers. Non-dynamic buffers are committed by CommitShaderResources + m_pPipelineState->GetRootSignature() + .CommitRootViews(*m_State.pCommittedResourceCache, + GraphCtx, + true, // IsCompute + m_ContextId, + this, + true, // CommitViews + true, // ProcessDynamicBuffers + false, // ProcessNonDynamicBuffers + false, // TransitionStates + false // ValidateStates + ); + } + } +#ifdef DILIGENT_DEVELOPMENT + else + { + if (m_pPipelineState->ContainsShaderResources()) + LOG_ERROR_MESSAGE("Pipeline state '", m_pPipelineState->GetDesc().Name, "' contains shader resources, but IDeviceContext::CommitShaderResources() was not called with non-null SRB"); + } +#endif +} + void DeviceContextD3D12Impl::DispatchCompute(const DispatchComputeAttribs& Attribs) { if (!DvpVerifyDispatchArguments(Attribs)) @@ -2139,6 +2173,46 @@ void DeviceContextD3D12Impl::TransitionOrVerifyTextureState(CommandContext& #endif } +void DeviceContextD3D12Impl::TransitionOrVerifyBLASState(CommandContext& CmdCtx, + BottomLevelASD3D12Impl& BLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName) +{ + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + if (BLAS.IsInKnownState() && !BLAS.CheckState(RequiredState)) + CmdCtx.TransitionResource(&BLAS, RequiredState); + } +#ifdef DILIGENT_DEVELOPMENT + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + DvpVerifyBLASState(BLAS, RequiredState, OperationName); + } +#endif +} + +void DeviceContextD3D12Impl::TransitionOrVerifyTLASState(CommandContext& CmdCtx, + TopLevelASD3D12Impl& TLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName) +{ + // AZ TODO: transit BLAS state too? + + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + if (TLAS.IsInKnownState() && !TLAS.CheckState(RequiredState)) + CmdCtx.TransitionResource(&TLAS, RequiredState); + } +#ifdef DILIGENT_DEVELOPMENT + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + DvpVerifyTLASState(TLAS, RequiredState, OperationName); + } +#endif +} + void DeviceContextD3D12Impl::TransitionTextureState(ITexture* pTexture, D3D12_RESOURCE_STATES State) { VERIFY_EXPR(pTexture != nullptr); @@ -2202,22 +2276,218 @@ void DeviceContextD3D12Impl::ResolveTextureSubresource(ITexture* void DeviceContextD3D12Impl::BuildBLAS(const BLASBuildAttribs& Attribs) { + if (!TDeviceContextBase::BuildBLAS(Attribs, 0)) + return; + + auto* pBLASD12 = ValidatedCast(Attribs.pBLAS); + auto* pScratchD12 = ValidatedCast(Attribs.pScratchBuffer); + auto& BLASDesc = pBLASD12->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); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC Desc = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& Inputs = Desc.Inputs; + std::vector Geometries; + + if (Attribs.pTriangleData != nullptr) + { + Geometries.resize(Attribs.TriangleDataCount); + + for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i) + { + auto& src = Attribs.pTriangleData[i]; + Uint32 j = pBLASD12->GetGeometryIndex(src.GeometryName); + auto& dst = Geometries.data()[j]; + auto& tri = dst.Triangles; + + if (j >= Geometries.size()) + { + UNEXPECTED("Failed to find geometry by name"); + continue; + } + + dst.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + dst.Flags = GeometryFlagsToD3D12RTGeometryFlags(src.Flags); + + auto* pVB = ValidatedCast(src.pVertexBuffer); + tri.VertexFormat = TypeToDXGI_Format(src.VertexValueType, src.VertexComponentCount, src.VertexValueType < VT_FLOAT16); + tri.VertexCount = src.VertexCount; + tri.VertexBuffer.StartAddress = pVB->GetGPUAddress() + src.VertexOffset; + tri.VertexBuffer.StrideInBytes = src.VertexStride; + + if (src.pIndexBuffer) + { + auto* pIB = ValidatedCast(src.pIndexBuffer); + tri.IndexBuffer = pIB->GetGPUAddress() + src.IndexOffset; + tri.IndexCount = src.IndexCount; + tri.IndexFormat = ValueTypeToIndexType(src.IndexType); + + TransitionOrVerifyBufferState(CmdCtx, *pIB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + } + else + { + tri.IndexFormat = DXGI_FORMAT_UNKNOWN; + tri.IndexBuffer = 0; + } + + if (src.pTransformBuffer) + { + VERIFY_EXPR(BLASDesc.pTriangles[j].AllowsTransforms); + + auto* pTB = ValidatedCast(src.pTransformBuffer); + tri.Transform3x4 = pTB->GetGPUAddress() + src.TransformBufferOffset; + + TransitionOrVerifyBufferState(CmdCtx, *pTB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + } + else + { + VERIFY_EXPR(!BLASDesc.pTriangles[j].AllowsTransforms); + tri.Transform3x4 = 0; + } + } + } + else if (Attribs.pBoxData != nullptr) + { + Geometries.resize(Attribs.BoxDataCount); + + for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i) + { + auto& src = Attribs.pBoxData[i]; + Uint32 j = pBLASD12->GetGeometryIndex(src.GeometryName); + auto& dst = Geometries.data()[j]; + auto& box = dst.AABBs; + + if (j >= Geometries.size()) + { + UNEXPECTED("Failed to find geometry by name"); + continue; + } + + dst.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + dst.Flags = GeometryFlagsToD3D12RTGeometryFlags(src.Flags); + + auto* pBB = ValidatedCast(src.pBoxBuffer); + box.AABBCount = src.BoxCount; + box.AABBs.StartAddress = pBB->GetGPUAddress() + src.BoxOffset; + box.AABBs.StrideInBytes = src.BoxStride; + + TransitionOrVerifyBufferState(CmdCtx, *pBB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + } + } + + Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + Inputs.NumDescs = static_cast(Geometries.size()); + Inputs.pGeometryDescs = Geometries.data(); + + Desc.DestAccelerationStructureData = pBLASD12->GetGPUAddress(); + Desc.ScratchAccelerationStructureData = pScratchD12->GetGPUAddress(); + Desc.SourceAccelerationStructureData = 0; + + CmdCtx.AsGraphicsContext4().BuildRaytracingAccelerationStructure(Desc, 0, nullptr); + ++m_State.NumCommands; } void DeviceContextD3D12Impl::BuildTLAS(const TLASBuildAttribs& Attribs) { + if (!TDeviceContextBase::BuildTLAS(Attribs, 0)) + return; + + 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(Attribs.pTLAS); + auto* pScratchD12 = ValidatedCast(Attribs.pScratchBuffer); + auto* pInstancesD12 = ValidatedCast(Attribs.pInstanceBuffer); + //auto& TLASDesc = pTLASD12->GetDesc(); + + 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); + + pTLASD12->SetInstanceData(Attribs.pInstances, Attribs.InstanceCount, Attribs.HitShadersPerInstance); + + // copy instance data into instance buffer + { + size_t Size = Attribs.InstanceCount * sizeof(D3D12_RAYTRACING_INSTANCE_DESC); + auto TmpSpace = m_DynamicHeap.Allocate(Size, 16, m_ContextFrameNumber); + void* pMappedInstances = TmpSpace.CPUAddress; + + for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) + { + auto& src = Attribs.pInstances[i]; + auto& dst = static_cast(pMappedInstances)[i]; + auto* pBLASD12 = ValidatedCast(src.pBLAS); + + static_assert(sizeof(dst.Transform) == sizeof(src.Transform), "size mismatch"); + std::memcpy(&dst.Transform, src.Transform, sizeof(dst.Transform)); + + dst.InstanceID = src.CustomId; + dst.InstanceContributionToHitGroupIndex = pTLASD12->GetInstanceDesc(src.InstanceName).ContributionToHitGroupIndex; // AZ TODO: optimize + dst.InstanceMask = src.Mask; + dst.Flags = InstanceFlagsToD3D12RTInstanceFlags(src.Flags); + dst.AccelerationStructure = pBLASD12->GetGPUAddress(); + + TransitionOrVerifyBLASState(CmdCtx, *pBLASD12, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + } + UpdateBufferRegion(pInstancesD12, TmpSpace, Attribs.InstanceBufferOffset, Size, Attribs.InstanceBufferTransitionMode); + } + TransitionOrVerifyBufferState(CmdCtx, *pInstancesD12, Attribs.InstanceBufferTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC Desc = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& Inputs = Desc.Inputs; + + Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + Inputs.NumDescs = Attribs.InstanceCount; + Inputs.InstanceDescs = pInstancesD12->GetGPUAddress(); + + Desc.DestAccelerationStructureData = pTLASD12->GetGPUAddress(); + Desc.ScratchAccelerationStructureData = pScratchD12->GetGPUAddress(); + Desc.SourceAccelerationStructureData = 0; + + CmdCtx.AsGraphicsContext4().BuildRaytracingAccelerationStructure(Desc, 0, nullptr); + ++m_State.NumCommands; } void DeviceContextD3D12Impl::CopyBLAS(const CopyBLASAttribs& Attribs) { + if (!TDeviceContextBase::CopyBLAS(Attribs, 0)) + return; + + // AZ TODO } void DeviceContextD3D12Impl::CopyTLAS(const CopyTLASAttribs& Attribs) { + if (!TDeviceContextBase::CopyTLAS(Attribs, 0)) + return; + + // AZ TODO } void DeviceContextD3D12Impl::TraceRays(const TraceRaysAttribs& Attribs) { + if (!TDeviceContextBase::TraceRays(Attribs, 0)) + return; + + D3D12_DISPATCH_RAYS_DESC Desc = {}; + + Desc.Width = Attribs.DimensionX; + Desc.Height = Attribs.DimensionY; + Desc.Depth = Attribs.DimensionZ; + + auto* pSBTD12 = ValidatedCast(Attribs.pSBT); + pSBTD12->GetD3D12AddressRangeAndStride(this, Attribs.TransitionMode, Desc.RayGenerationShaderRecord, Desc.MissShaderTable, Desc.HitGroupTable, Desc.CallableShaderTable); + + auto& CmdCtx = GetCmdContext().AsGraphicsContext4(); + PrepareForDispatchRays(CmdCtx); + + CmdCtx.DispatchRays(Desc); + ++m_State.NumCommands; } } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp b/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp index be5c68eb..0da4470b 100644 --- a/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp +++ b/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp @@ -113,7 +113,7 @@ GenerateMipsHelper::GenerateMipsHelper(ID3D12Device* pd3d12Device) void GenerateMipsHelper::GenerateMips(ID3D12Device* pd3d12Device, TextureViewD3D12Impl* pTexView, CommandContext& Ctx) const { auto& ComputeCtx = Ctx.AsComputeContext(); - ComputeCtx.SetRootSignature(m_pGenerateMipsRS); + ComputeCtx.SetComputeRootSignature(m_pGenerateMipsRS); auto* pTexD3D12 = pTexView->GetTexture(); const auto& TexDesc = pTexD3D12->GetDesc(); const auto& ViewDesc = pTexView->GetDesc(); diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp index efae7b37..9cc7faa5 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -877,9 +877,9 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou if (Attrib.CommitResources) { if (m_Desc.IsAnyGraphicsPipeline()) - CmdCtx.AsGraphicsContext().SetRootSignature(GetD3D12RootSignature()); + CmdCtx.AsGraphicsContext().SetGraphicsRootSignature(GetD3D12RootSignature()); else - CmdCtx.AsComputeContext().SetRootSignature(GetD3D12RootSignature()); + CmdCtx.AsComputeContext().SetComputeRootSignature(GetD3D12RootSignature()); } return nullptr; } @@ -906,9 +906,9 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou if (Attrib.CommitResources) { if (m_Desc.IsAnyGraphicsPipeline()) - CmdCtx.AsGraphicsContext().SetRootSignature(GetD3D12RootSignature()); + CmdCtx.AsGraphicsContext().SetGraphicsRootSignature(GetD3D12RootSignature()); else - CmdCtx.AsComputeContext().SetRootSignature(GetD3D12RootSignature()); + CmdCtx.AsComputeContext().SetComputeRootSignature(GetD3D12RootSignature()); if (Attrib.TransitionResources) { diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 9feabb6a..f8f545e7 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -40,6 +40,9 @@ #include "QueryD3D12Impl.hpp" #include "RenderPassD3D12Impl.hpp" #include "FramebufferD3D12Impl.hpp" +#include "BottomLevelASD3D12Impl.hpp" +#include "TopLevelASD3D12Impl.hpp" +#include "ShaderBindingTableD3D12Impl.hpp" #include "EngineMemory.h" namespace Diligent @@ -137,9 +140,9 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo sizeof(QueryD3D12Impl), sizeof(RenderPassD3D12Impl), sizeof(FramebufferD3D12Impl), - 0, - 0, - 0 + sizeof(BottomLevelASD3D12Impl), + sizeof(TopLevelASD3D12Impl), + sizeof(ShaderBindingTableD3D12Impl) } }, m_pd3d12Device {pd3d12Device}, @@ -725,19 +728,37 @@ void RenderDeviceD3D12Impl::CreateFramebuffer(const FramebufferDesc& Desc, IFram void RenderDeviceD3D12Impl::CreateBLAS(const BottomLevelASDesc& Desc, IBottomLevelAS** ppBLAS) { - // AZ TODO + CreateDeviceObject("BottomLevelAS", Desc, ppBLAS, + [&]() // + { + BottomLevelASD3D12Impl* pBottomLevelASVk(NEW_RC_OBJ(m_BLASAllocator, "BottomLevelASD3D12Impl instance", BottomLevelASD3D12Impl)(this, Desc)); + pBottomLevelASVk->QueryInterface(IID_BottomLevelAS, reinterpret_cast(ppBLAS)); + OnCreateDeviceObject(pBottomLevelASVk); + }); } void RenderDeviceD3D12Impl::CreateTLAS(const TopLevelASDesc& Desc, ITopLevelAS** ppTLAS) { - // AZ TODO + CreateDeviceObject("TopLevelAS", Desc, ppTLAS, + [&]() // + { + TopLevelASD3D12Impl* pTopLevelASVk(NEW_RC_OBJ(m_TLASAllocator, "TopLevelASD3D12Impl instance", TopLevelASD3D12Impl)(this, Desc)); + pTopLevelASVk->QueryInterface(IID_TopLevelAS, reinterpret_cast(ppTLAS)); + OnCreateDeviceObject(pTopLevelASVk); + }); } void RenderDeviceD3D12Impl::CreateSBT(const ShaderBindingTableDesc& Desc, IShaderBindingTable** ppSBT) { - // AZ TODO + CreateDeviceObject("ShaderBindingTable", Desc, ppSBT, + [&]() // + { + ShaderBindingTableD3D12Impl* pSBTVk(NEW_RC_OBJ(m_SBTAllocator, "ShaderBindingTableD3D12Impl instance", ShaderBindingTableD3D12Impl)(this, Desc)); + pSBTVk->QueryInterface(IID_ShaderBindingTable, reinterpret_cast(ppSBT)); + OnCreateDeviceObject(pSBTVk); + }); } DescriptorHeapAllocation RenderDeviceD3D12Impl::AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count /*= 1*/) diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp index 35274af3..d0db2201 100644 --- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp @@ -33,6 +33,7 @@ #include "CommandContext.hpp" #include "RenderDeviceD3D12Impl.hpp" #include "TextureD3D12Impl.hpp" +#include "TopLevelASD3D12Impl.hpp" #include "D3D12TypeConversions.hpp" #include "HashUtils.hpp" @@ -702,6 +703,10 @@ __forceinline void TransitionResource(CommandContext& Ctx, case CachedResourceType::AccelStruct: { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + auto* pTLASD3D12 = Res.pObject.RawPtr(); + if (pTLASD3D12->IsInKnownState() && !pTLASD3D12->CheckState(RESOURCE_STATE_RAY_TRACING)) + Ctx.TransitionResource(pTLASD3D12, RESOURCE_STATE_RAY_TRACING); } break; @@ -806,6 +811,16 @@ void RootSignature::DvpVerifyResourceState(const ShaderResourceCacheD3D12::Resou case CachedResourceType::AccelStruct: { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + const auto* pTLASD3D12 = Res.pObject.RawPtr(); + if (pTLASD3D12->IsInKnownState() && !pTLASD3D12->CheckState(RESOURCE_STATE_RAY_TRACING)) + { + LOG_ERROR_MESSAGE("TLAS '", pTLASD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_RAY_TRACING state. Actual state: ", + GetResourceStateString(pTLASD3D12->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state " + "with IDeviceContext::TransitionResourceStates()."); + } } break; diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp new file mode 100644 index 00000000..3727913f --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp @@ -0,0 +1,202 @@ +/* + * 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. + */ + +#include "pch.h" +#include "ShaderBindingTableD3D12Impl.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "DeviceContextD3D12Impl.hpp" +#include "D3D12TypeConversions.hpp" +#include "GraphicsAccessories.hpp" +#include "DXGITypeConversions.hpp" +#include "EngineMemory.h" +#include "StringTools.hpp" + +namespace Diligent +{ + +ShaderBindingTableD3D12Impl::ShaderBindingTableD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const ShaderBindingTableDesc& Desc, + bool bIsDeviceInternal) : + TShaderBindingTableBase{pRefCounters, pDeviceD3D12, Desc, bIsDeviceInternal} +{ + ValidateDesc(Desc); + + m_ShaderRecordStride = m_Desc.ShaderRecordSize + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; +} + +ShaderBindingTableD3D12Impl::~ShaderBindingTableD3D12Impl() +{ +} + +IMPLEMENT_QUERY_INTERFACE(ShaderBindingTableD3D12Impl, IID_ShaderBindingTableD3D12, TShaderBindingTableBase) + +void ShaderBindingTableD3D12Impl::ValidateDesc(const ShaderBindingTableDesc& Desc) const +{ + if (Desc.ShaderRecordSize + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES > D3D12_RAYTRACING_MAX_SHADER_RECORD_STRIDE) + { + LOG_ERROR_AND_THROW("Description of Shader binding table '", (Desc.Name ? Desc.Name : ""), + "' is invalid: ShaderRecordSize is too big, max size is: ", D3D12_RAYTRACING_MAX_SHADER_RECORD_STRIDE - D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES); + } +} + +void ShaderBindingTableD3D12Impl::Verify() const +{ + // AZ TODO +} + +void ShaderBindingTableD3D12Impl::Reset(const ShaderBindingTableDesc& Desc) +{ + m_RayGenShaderRecord.clear(); + m_MissShadersRecord.clear(); + m_CallableShadersRecord.clear(); + m_HitGroupsRecord.clear(); + m_Changed = true; + + try + { + ValidateShaderBindingTableDesc(Desc); + ValidateDesc(Desc); + } + catch (const std::runtime_error&) + { + // AZ TODO + return; + } + + m_Desc = Desc; + m_ShaderRecordStride = m_Desc.ShaderRecordSize + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; +} + +void ShaderBindingTableD3D12Impl::ResetHitGroups(Uint32 HitShadersPerInstance) +{ + // AZ TODO +} + +void ShaderBindingTableD3D12Impl::BindAll(const BindAllAttribs& Attribs) +{ + // AZ TODO +} + +void ShaderBindingTableD3D12Impl::GetD3D12AddressRangeAndStride(IDeviceContextD3D12* pContext, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE& RaygenShaderBindingTable, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE& MissShaderBindingTable, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE& HitShaderBindingTable, + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE& CallableShaderBindingTable) +{ + const auto AlignToLarger = [](size_t offset) -> Uint32 { + return Align(static_cast(offset), static_cast(D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT)); + }; + + const Uint32 RayGenOffset = 0; + const Uint32 MissShaderOffset = AlignToLarger(m_RayGenShaderRecord.size()); + const Uint32 HitGroupOffset = AlignToLarger(MissShaderOffset + m_MissShadersRecord.size()); + const Uint32 CallableShadersOffset = AlignToLarger(HitGroupOffset + m_HitGroupsRecord.size()); + const Uint32 BufSize = AlignToLarger(CallableShadersOffset + m_CallableShadersRecord.size()); + + // recreate buffer + if (m_pBuffer == nullptr || m_pBuffer->GetDesc().uiSizeInBytes < BufSize) + { + m_pBuffer = nullptr; + + String BuffName = String{GetDesc().Name} + " - internal buffer"; + BufferDesc BuffDesc; + BuffDesc.Name = BuffName.c_str(); + BuffDesc.Usage = USAGE_DEFAULT; + BuffDesc.BindFlags = BIND_RAY_TRACING; + BuffDesc.uiSizeInBytes = BufSize; + + GetDevice()->CreateBuffer(BuffDesc, nullptr, &m_pBuffer); + VERIFY_EXPR(m_pBuffer != nullptr); + } + + if (m_pBuffer == nullptr) + return; // something goes wrong + + const D3D12_GPU_VIRTUAL_ADDRESS BuffHandle = m_pBuffer.RawPtr()->GetGPUAddress(0, ValidatedCast(pContext)); + + if (m_RayGenShaderRecord.size()) + { + RaygenShaderBindingTable.StartAddress = BuffHandle + RayGenOffset; + RaygenShaderBindingTable.SizeInBytes = m_RayGenShaderRecord.size(); + } + + if (m_MissShadersRecord.size()) + { + MissShaderBindingTable.StartAddress = BuffHandle + MissShaderOffset; + MissShaderBindingTable.SizeInBytes = m_MissShadersRecord.size(); + MissShaderBindingTable.StrideInBytes = m_ShaderRecordStride; + } + + if (m_HitGroupsRecord.size()) + { + HitShaderBindingTable.StartAddress = BuffHandle + HitGroupOffset; + HitShaderBindingTable.SizeInBytes = m_HitGroupsRecord.size(); + HitShaderBindingTable.StrideInBytes = m_ShaderRecordStride; + } + + if (m_CallableShadersRecord.size()) + { + CallableShaderBindingTable.StartAddress = BuffHandle + CallableShadersOffset; + CallableShaderBindingTable.SizeInBytes = m_CallableShadersRecord.size(); + CallableShaderBindingTable.StrideInBytes = m_ShaderRecordStride; + } + + if (!m_Changed) + return; + + m_Changed = false; + + // update buffer data + if (m_RayGenShaderRecord.size()) + pContext->UpdateBuffer(m_pBuffer, RayGenOffset, static_cast(m_RayGenShaderRecord.size()), m_RayGenShaderRecord.data(), TransitionMode); + + if (m_MissShadersRecord.size()) + pContext->UpdateBuffer(m_pBuffer, MissShaderOffset, static_cast(m_MissShadersRecord.size()), m_MissShadersRecord.data(), TransitionMode); + + if (m_HitGroupsRecord.size()) + pContext->UpdateBuffer(m_pBuffer, HitGroupOffset, static_cast(m_HitGroupsRecord.size()), m_HitGroupsRecord.data(), TransitionMode); + + if (m_CallableShadersRecord.size()) + pContext->UpdateBuffer(m_pBuffer, CallableShadersOffset, static_cast(m_CallableShadersRecord.size()), m_CallableShadersRecord.data(), TransitionMode); + + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + StateTransitionDesc Barrier; + Barrier.pResource = m_pBuffer; + Barrier.NewState = RESOURCE_STATE_RAY_TRACING; + Barrier.UpdateResourceState = true; + pContext->TransitionResourceStates(1, &Barrier); + } + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + VERIFY_EXPR(m_pBuffer->GetState() == RESOURCE_STATE_RAY_TRACING); + } +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp index b4bb1f72..6dbdb97f 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp @@ -40,6 +40,7 @@ #include "ShaderResourceVariableBase.hpp" #include "ShaderVariableD3DBase.hpp" #include "LinearAllocator.hpp" +#include "TopLevelASD3D12.h" namespace Diligent { @@ -622,6 +623,35 @@ void ShaderResourceLayoutD3D12::D3D12Resource::CacheAccelStruct(IDeviceObject* Uint32 ArrayIndex, D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) const { + VERIFY(Attribs.IsValidBindPoint(), "Invalid bind point"); + VERIFY_EXPR(ArrayIndex < Attribs.BindCount); + + RefCntAutoPtr pTLASD3D12(pTLAS, IID_TopLevelASD3D12); + if (pTLASD3D12) + { + if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) + { + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. + return; + } + + DstRes.Type = GetResType(); + DstRes.CPUDescriptorHandle = pTLASD3D12->GetCPUDescriptorHandle(); + VERIFY(DstRes.CPUDescriptorHandle.ptr != 0, "No relevant D3D12 resource"); + + if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) + { + // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and + // the descriptor is copied by the RootSignature when resources are committed + VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); + + ID3D12Device* pd3d12Device = ParentResLayout.m_pd3d12Device; + pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + + DstRes.pObject = std::move(pTLASD3D12); + } } const ShaderResourceLayoutD3D12::D3D12Resource& ShaderResourceLayoutD3D12::GetAssignedSampler(const D3D12Resource& TexSrv) const diff --git a/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp new file mode 100644 index 00000000..5f411640 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#include "pch.h" +#include "TopLevelASD3D12Impl.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "DeviceContextD3D12Impl.hpp" +#include "D3D12TypeConversions.hpp" +#include "GraphicsAccessories.hpp" +#include "DXGITypeConversions.hpp" +#include "EngineMemory.h" +#include "StringTools.hpp" + +namespace Diligent +{ + +TopLevelASD3D12Impl::TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const TopLevelASDesc& Desc, + bool bIsDeviceInternal) : + TTopLevelASBase{pRefCounters, pDeviceD3D12, Desc, bIsDeviceInternal} +{ + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO TopLevelPrebuildInfo = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS TopLevelInputs = {}; + + TopLevelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + TopLevelInputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE; + TopLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + TopLevelInputs.NumDescs = Desc.MaxInstanceCount; + + VERIFY_EXPR(Desc.MaxInstanceCount <= D3D12_RAYTRACING_MAX_INSTANCES_PER_TOP_LEVEL_ACCELERATION_STRUCTURE); + + auto* pd3d12Device = pDeviceD3D12->GetD3D12Device5(); + + pd3d12Device->GetRaytracingAccelerationStructurePrebuildInfo(&TopLevelInputs, &TopLevelPrebuildInfo); + if (TopLevelPrebuildInfo.ResultDataMaxSizeInBytes == 0) + LOG_ERROR_AND_THROW("Failed to get ray tracing acceleration structure prebuild info"); + + D3D12_HEAP_PROPERTIES HeapProps; + HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + HeapProps.CreationNodeMask = 1; + HeapProps.VisibleNodeMask = 1; + + D3D12_RESOURCE_DESC ASDesc = {}; + ASDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + ASDesc.Alignment = 0; + ASDesc.Width = TopLevelPrebuildInfo.ResultDataMaxSizeInBytes; + ASDesc.Height = 1; + ASDesc.DepthOrArraySize = 1; + ASDesc.MipLevels = 1; + ASDesc.Format = DXGI_FORMAT_UNKNOWN; + ASDesc.SampleDesc.Count = 1; + ASDesc.SampleDesc.Quality = 0; + ASDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + ASDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + auto hr = pd3d12Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, + &ASDesc, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, nullptr, + __uuidof(m_pd3d12Resource), + reinterpret_cast(static_cast(&m_pd3d12Resource))); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create D3D12 Top-level acceleration structure"); + + if (*m_Desc.Name != 0) + m_pd3d12Resource->SetName(WidenString(m_Desc.Name).c_str()); + + m_ScratchSize.Build = static_cast(TopLevelPrebuildInfo.ScratchDataSizeInBytes); + m_ScratchSize.Update = static_cast(TopLevelPrebuildInfo.UpdateScratchDataSizeInBytes); + + m_DescriptorHandle = pDeviceD3D12->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc; + SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; + SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + SRVDesc.Format = DXGI_FORMAT_UNKNOWN; + SRVDesc.RaytracingAccelerationStructure.Location = GetGPUAddress(); + pd3d12Device->CreateShaderResourceView(nullptr, &SRVDesc, m_DescriptorHandle.GetCpuHandle()); +} + +TopLevelASD3D12Impl::~TopLevelASD3D12Impl() +{ + // D3D12 object can only be destroyed when it is no longer used by the GPU + auto* pDeviceD3D12Impl = ValidatedCast(GetDevice()); + pDeviceD3D12Impl->SafeReleaseDeviceObject(std::move(m_pd3d12Resource), m_Desc.CommandQueueMask); +} + +IMPLEMENT_QUERY_INTERFACE(TopLevelASD3D12Impl, IID_TopLevelASD3D12, TTopLevelASBase) + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp index 8f1b4c37..0b2154e6 100644 --- a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp @@ -40,6 +40,8 @@ #include "FramebufferGLImpl.hpp" #include "RenderPassGLImpl.hpp" #include "PipelineStateGLImpl.hpp" +#include "BottomLevelASBase.hpp" +#include "TopLevelASBase.hpp" namespace Diligent { @@ -53,6 +55,8 @@ struct DeviceContextGLImplTraits using QueryType = QueryGLImpl; using FramebufferType = FramebufferGLImpl; using RenderPassType = RenderPassGLImpl; + using BottomLevelASType = BottomLevelASBase; + using TopLevelASType = TopLevelASBase; }; /// Device context implementation in OpenGL backend. diff --git a/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp index eb485370..e907337d 100644 --- a/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp @@ -50,10 +50,20 @@ public: bool bIsDeviceInternal = false); ~BottomLevelASVkImpl(); + /// Implementation of IBottomLevelAS::GetScratchBufferSizes() in Vulkan backend. virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override { return m_ScratchSize; } + /// Implementation of IBottomLevelAS::GetNativeHandle() in Vulkan backend. + virtual void* DILIGENT_CALL_TYPE GetNativeHandle() override final + { + auto Handle = GetVkBLAS(); + return reinterpret_cast(Handle); + } + + /// Implementation of IBottomLevelASVk::GetVkBLAS(). virtual VkAccelerationStructureKHR DILIGENT_CALL_TYPE GetVkBLAS() const override { return m_VulkanBLAS; } + /// Implementation of IBottomLevelASVk::GetVkDeviceAddress(). virtual VkDeviceAddress DILIGENT_CALL_TYPE GetVkDeviceAddress() const override { return m_DeviceAddress; } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BottomLevelASVk, TBottomLevelASBase); @@ -62,6 +72,7 @@ private: VkDeviceAddress m_DeviceAddress = 0; VulkanUtilities::AccelStructWrapper m_VulkanBLAS; VulkanUtilities::VulkanMemoryAllocation m_MemoryAllocation; + VkDeviceSize m_MemoryAlignedOffset = 0; ScratchBufferSizes m_ScratchSize; }; diff --git a/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.hpp b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.hpp index 98438da3..41a8cac3 100644 --- a/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.hpp @@ -137,17 +137,7 @@ public: std::string PoolName, std::vector PoolSizes, uint32_t MaxSets, - bool AllowFreeing) noexcept: - m_DeviceVkImpl{DeviceVkImpl }, - m_PoolName {std::move(PoolName) }, - m_PoolSizes (std::move(PoolSizes)), - m_MaxSets {MaxSets }, - m_AllowFreeing{AllowFreeing } - { -#ifdef DILIGENT_DEVELOPMENT - m_AllocatedPoolCounter = 0; -#endif - } + bool AllowFreeing) noexcept; ~DescriptorPoolManager(); DescriptorPoolManager (const DescriptorPoolManager&) = delete; @@ -175,9 +165,9 @@ protected: RenderDeviceVkImpl& m_DeviceVkImpl; const std::string m_PoolName; - const std::vector m_PoolSizes; - const uint32_t m_MaxSets; - const bool m_AllowFreeing; + std::vector m_PoolSizes; + const uint32_t m_MaxSets; + const bool m_AllowFreeing; std::mutex m_Mutex; std::deque m_Pools; diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp index 26142ba0..40e19d80 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -50,6 +50,9 @@ #include "HashUtils.hpp" #include "ManagedVulkanObject.hpp" #include "QueryManagerVk.hpp" +#include "BottomLevelASVkImpl.hpp" +#include "TopLevelASVkImpl.hpp" +#include "ShaderBindingTableVkImpl.hpp" namespace Diligent @@ -65,6 +68,8 @@ struct DeviceContextVkImplTraits using QueryType = QueryVkImpl; using FramebufferType = FramebufferVkImpl; using RenderPassType = RenderPassVkImpl; + using BottomLevelASType = BottomLevelASVkImpl; + using TopLevelASType = TopLevelASVkImpl; }; /// Device context implementation in Vulkan backend. @@ -294,6 +299,20 @@ public: virtual void DILIGENT_CALL_TYPE BufferMemoryBarrier(IBuffer* pBuffer, VkAccessFlags NewAccessFlags) override final; + // Transitions BLAS state from OldState to NewState, and optionally updates internal state. + // If OldState == RESOURCE_STATE_UNKNOWN, internal BLAS state is used as old state. + void TransitionBLASState(BottomLevelASVkImpl& BLAS, + RESOURCE_STATE OldState, + RESOURCE_STATE NewState, + bool UpdateInternalState); + + // Transitions TLAS state from OldState to NewState, and optionally updates internal state. + // If OldState == RESOURCE_STATE_UNKNOWN, internal TLAS state is used as old state. + void TransitionTLASState(TopLevelASVkImpl& TLAS, + RESOURCE_STATE OldState, + RESOURCE_STATE NewState, + bool UpdateInternalState); + void AddWaitSemaphore(ManagedSemaphore* pWaitSemaphore, VkPipelineStageFlags WaitDstStageMask) { VERIFY_EXPR(pWaitSemaphore != nullptr); @@ -386,6 +405,15 @@ private: VkImageLayout ExpectedLayout, const char* OperationName); + __forceinline void TransitionOrVerifyBLASState(BottomLevelASVkImpl& BLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName); + + __forceinline void TransitionOrVerifyTLASState(TopLevelASVkImpl& TLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName); __forceinline void EnsureVkCmdBuffer() { @@ -438,6 +466,7 @@ private: __forceinline void PrepareForIndexedDraw(DRAW_FLAGS Flags, VALUE_TYPE IndexType); __forceinline BufferVkImpl* PrepareIndirectDrawAttribsBuffer(IBuffer* pAttribsBuffer, RESOURCE_STATE_TRANSITION_MODE TransitonMode); __forceinline void PrepareForDispatchCompute(); + __forceinline void PrepareForRayTracing(); void DvpLogRenderPass_PSOMismatch(); diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index 6abe5213..e13f1a76 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp @@ -178,16 +178,16 @@ public: FramebufferCache& GetFramebufferCache() { return m_FramebufferCache; } RenderPassCache& GetImplicitRenderPassCache() { return m_ImplicitRenderPassCache; } - VulkanUtilities::VulkanMemoryAllocation AllocateMemory(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProperties) + VulkanUtilities::VulkanMemoryAllocation AllocateMemory(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProperties, VkMemoryAllocateFlags AllocateFlags = 0) { - return m_MemoryMgr.Allocate(MemReqs, MemoryProperties); + return m_MemoryMgr.Allocate(MemReqs, MemoryProperties, AllocateFlags); } - VulkanUtilities::VulkanMemoryAllocation AllocateMemory(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex) + VulkanUtilities::VulkanMemoryAllocation AllocateMemory(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, VkMemoryAllocateFlags AllocateFlags = 0) { const auto& MemoryProps = m_PhysicalDevice->GetMemoryProperties(); VERIFY_EXPR(MemoryTypeIndex < MemoryProps.memoryTypeCount); const auto MemoryFlags = MemoryProps.memoryTypes[MemoryTypeIndex].propertyFlags; - return m_MemoryMgr.Allocate(Size, Alignment, MemoryTypeIndex, (MemoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0); + return m_MemoryMgr.Allocate(Size, Alignment, MemoryTypeIndex, (MemoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0, AllocateFlags); } VulkanUtilities::VulkanMemoryManager& GetGlobalMemoryManager() { return m_MemoryMgr; } diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp index 92d83160..1b2db950 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp @@ -30,20 +30,20 @@ /// \file /// Definition of the Diligent::ShaderBindingTableVkImpl class -#include "BufferVkImpl.hpp" #include "RenderDeviceVk.h" #include "RenderDeviceVkImpl.hpp" #include "ShaderBindingTableVk.h" #include "ShaderBindingTableBase.hpp" +#include "PipelineStateVkImpl.hpp" #include "VulkanUtilities/VulkanObjectWrappers.hpp" namespace Diligent { -class ShaderBindingTableVkImpl final : public ShaderBindingTableBase +class ShaderBindingTableVkImpl final : public ShaderBindingTableBase { public: - using TShaderBindingTableBase = ShaderBindingTableBase; + using TShaderBindingTableBase = ShaderBindingTableBase; ShaderBindingTableVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, @@ -56,37 +56,14 @@ public: virtual void DILIGENT_CALL_TYPE Reset(const ShaderBindingTableDesc& Desc) override; virtual void DILIGENT_CALL_TYPE ResetHitGroups(Uint32 HitShadersPerInstance) override; - - virtual void DILIGENT_CALL_TYPE BindRayGenShader(const char* ShaderGroupName, const void* Data, Uint32 DataSize) override; - - virtual void DILIGENT_CALL_TYPE BindMissShader(const char* ShaderGroupName, Uint32 MissIndex, const void* Data, Uint32 DataSize) override; - - virtual void DILIGENT_CALL_TYPE BindHitGroup(ITopLevelAS* pTLAS, - const char* InstanceName, - const char* GeometryName, - Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data, - Uint32 DataSize) override; - - virtual void DILIGENT_CALL_TYPE BindHitGroups(ITopLevelAS* pTLAS, - const char* InstanceName, - Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data, - Uint32 DataSize) override; - - virtual void DILIGENT_CALL_TYPE BindCallableShader(Uint32 Index, - const char* ShaderName, - const void* Data, - Uint32 DataSize) override; - virtual void DILIGENT_CALL_TYPE BindAll(const BindAllAttribs& Attribs) override; - virtual void DILIGENT_CALL_TYPE GetVkStridedBufferRegions(VkStridedBufferRegionKHR& RaygenShaderBindingTable, - VkStridedBufferRegionKHR& MissShaderBindingTable, - VkStridedBufferRegionKHR& HitShaderBindingTable, - VkStridedBufferRegionKHR& CallableShaderBindingTable) override; + virtual void DILIGENT_CALL_TYPE GetVkStridedBufferRegions(IDeviceContextVk* pContext, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + VkStridedBufferRegionKHR& RaygenShaderBindingTable, + VkStridedBufferRegionKHR& MissShaderBindingTable, + VkStridedBufferRegionKHR& HitShaderBindingTable, + VkStridedBufferRegionKHR& CallableShaderBindingTable) override; IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderBindingTableVk, TShaderBindingTableBase); @@ -94,17 +71,7 @@ private: void ValidateDesc(const ShaderBindingTableDesc& Desc) const; private: - RefCntAutoPtr m_pBuffer; - std::vector m_ShaderRecords; - - Uint32 m_MissShadersOffset = 0; - Uint32 m_HitGroupsOffset = 0; - Uint32 m_CallbaleShadersOffset = 0; - Uint32 m_MissShaderCount = 0; - Uint32 m_HitGroupCount = 0; - Uint32 m_CallableShaderCount = 0; - Uint32 m_ShaderGroupHandleSize = 0; - Uint32 m_ShaderGroupBaseAlignment = 0; + RefCntAutoPtr m_pBuffer; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp index 11c1ebef..b2801eca 100644 --- a/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp @@ -50,18 +50,27 @@ public: bool bIsDeviceInternal = false); ~TopLevelASVkImpl(); + /// Implementation of ITopLevelAS::GetScratchBufferSizes() in Vulkan backend. virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override { return m_ScratchSize; } - virtual VkAccelerationStructureKHR DILIGENT_CALL_TYPE GetVkTLAS() const override { return m_VulkanTLAS; } + /// Implementation of ITopLevelAS::GetNativeHandle() in Vulkan backend. + virtual void* DILIGENT_CALL_TYPE GetNativeHandle() override final + { + auto Handle = GetVkTLAS(); + return reinterpret_cast(Handle); + } - virtual VkDeviceAddress DILIGENT_CALL_TYPE GetVkDeviceAddress() const override { return m_DeviceAddress; } + /// Implementation of ITopLevelASVk::GetVkTLAS(). + virtual VkAccelerationStructureKHR DILIGENT_CALL_TYPE GetVkTLAS() const override { return m_VulkanTLAS; } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelASVk, TTopLevelASBase); + const VkAccelerationStructureKHR* GetVkTLASPtr() const { return &m_VulkanTLAS; } + private: - VkDeviceAddress m_DeviceAddress = 0; VulkanUtilities::AccelStructWrapper m_VulkanTLAS; VulkanUtilities::VulkanMemoryAllocation m_MemoryAllocation; + VkDeviceSize m_MemoryAlignedOffset = 0; ScratchBufferSizes m_ScratchSize; }; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp index e88c93d2..8f90a914 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp @@ -65,8 +65,9 @@ VkSamplerMipmapMode FilterTypeToVkMipmapMode(FILTER_TYPE FilterType); VkSamplerAddressMode AddressModeToVkAddressMode(TEXTURE_ADDRESS_MODE AddressMode); VkBorderColor BorderColorToVkBorderColor(const Float32 BorderColor[]); -VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags); -VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsideRenderPass = false); +VkPipelineStageFlags ResourceStateFlagsToVkPipelineStageFlags(RESOURCE_STATE StateFlags, VkPipelineStageFlags ShaderStages); +VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags); +VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsideRenderPass = false); RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlags AccessFlags); RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout); diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp index 0cd6de63..50a4c99f 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp @@ -36,8 +36,8 @@ namespace VulkanUtilities class VulkanCommandBuffer { public: - VulkanCommandBuffer(VkPipelineStageFlags EnabledGraphicsShaderStages) noexcept : - m_EnabledGraphicsShaderStages{EnabledGraphicsShaderStages} + VulkanCommandBuffer(VkPipelineStageFlags EnabledShaderStages) noexcept : + m_EnabledShaderStages{EnabledShaderStages} {} // clang-format off @@ -280,6 +280,17 @@ public: } } + __forceinline void BindRayTracingPipeline(VkPipeline RayTracingPipeline) + { + // 9.8 + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + if (m_State.RayTracingPipeline != RayTracingPipeline) + { + vkCmdBindPipeline(m_VkCmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, RayTracingPipeline); + m_State.RayTracingPipeline = RayTracingPipeline; + } + } + __forceinline void SetViewports(uint32_t FirstViewport, uint32_t ViewportCount, const VkViewport* pViewports) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); @@ -331,7 +342,7 @@ public: VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange, - VkPipelineStageFlags EnabledGraphicsShaderStages, + VkPipelineStageFlags EnabledShaderStages, VkPipelineStageFlags SrcStages = 0, VkPipelineStageFlags DestStages = 0); @@ -349,7 +360,7 @@ public: // dependencies between attachments EndRenderPass(); } - TransitionImageLayout(m_VkCmdBuffer, Image, OldLayout, NewLayout, SubresRange, m_EnabledGraphicsShaderStages, SrcStages, DestStages); + TransitionImageLayout(m_VkCmdBuffer, Image, OldLayout, NewLayout, SubresRange, m_EnabledShaderStages, SrcStages, DestStages); } @@ -357,7 +368,7 @@ public: VkBuffer Buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, - VkPipelineStageFlags EnabledGraphicsShaderStages, + VkPipelineStageFlags EnabledShaderStages, VkPipelineStageFlags SrcStages = 0, VkPipelineStageFlags DestStages = 0); @@ -374,7 +385,31 @@ public: // dependencies between attachments EndRenderPass(); } - BufferMemoryBarrier(m_VkCmdBuffer, Buffer, srcAccessMask, dstAccessMask, m_EnabledGraphicsShaderStages, SrcStages, DestStages); + BufferMemoryBarrier(m_VkCmdBuffer, Buffer, srcAccessMask, dstAccessMask, m_EnabledShaderStages, SrcStages, DestStages); + } + + + // for Acceleration structures + static void ASMemoryBarrier(VkCommandBuffer CmdBuffer, + VkAccessFlags srcAccessMask, + VkAccessFlags dstAccessMask, + VkPipelineStageFlags EnabledShaderStages, + VkPipelineStageFlags SrcStages = 0, + VkPipelineStageFlags DestStages = 0); + + __forceinline void ASMemoryBarrier(VkAccessFlags srcAccessMask, + VkAccessFlags dstAccessMask, + VkPipelineStageFlags SrcStages = 0, + VkPipelineStageFlags DestStages = 0) + { + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + if (m_State.RenderPass != VK_NULL_HANDLE) + { + // Image layout transitions within a render pass execute + // dependencies between attachments + EndRenderPass(); + } + ASMemoryBarrier(m_VkCmdBuffer, srcAccessMask, dstAccessMask, m_EnabledShaderStages, SrcStages, DestStages); } __forceinline void BindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, @@ -575,6 +610,12 @@ public: const VkAccelerationStructureBuildOffsetInfoKHR* const* ppOffsetInfos) { #if DILIGENT_USE_VOLK + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + if (m_State.RenderPass != VK_NULL_HANDLE) + { + // Build AS operations must be performed outside of render pass. + EndRenderPass(); + } vkCmdBuildAccelerationStructureKHR(m_VkCmdBuffer, infoCount, pInfos, ppOffsetInfos); #else UNSUPPORTED("Ray tracing is not supported when vulkan library is linked statically"); @@ -584,6 +625,12 @@ public: __forceinline void CopyAccelerationStructure(const VkCopyAccelerationStructureInfoKHR& Info) { #if DILIGENT_USE_VOLK + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + if (m_State.RenderPass != VK_NULL_HANDLE) + { + // Copy AS operations must be performed outside of render pass. + EndRenderPass(); + } vkCmdCopyAccelerationStructureKHR(m_VkCmdBuffer, &Info); #else UNSUPPORTED("Ray tracing is not supported when vulkan library is linked statically"); @@ -599,6 +646,9 @@ public: uint32_t depth) { #if DILIGENT_USE_VOLK + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + VERIFY(m_State.RayTracingPipeline != VK_NULL_HANDLE, "No ray tracing pipeline bound"); + vkCmdTraceRaysKHR(m_VkCmdBuffer, &RaygenShaderBindingTable, &MissShaderBindingTable, &HitShaderBindingTable, &CallableShaderBindingTable, width, height, depth); #else UNSUPPORTED("Ray tracing is not supported when vulkan library is linked statically"); @@ -613,12 +663,15 @@ public: } VkCommandBuffer GetVkCmdBuffer() const { return m_VkCmdBuffer; } + VkPipelineStageFlags GetEnabledShaderStages() const { return m_EnabledShaderStages; } + struct StateCache { VkRenderPass RenderPass = VK_NULL_HANDLE; VkFramebuffer Framebuffer = VK_NULL_HANDLE; VkPipeline GraphicsPipeline = VK_NULL_HANDLE; VkPipeline ComputePipeline = VK_NULL_HANDLE; + VkPipeline RayTracingPipeline = VK_NULL_HANDLE; VkBuffer IndexBuffer = VK_NULL_HANDLE; VkDeviceSize IndexBufferOffset = 0; VkIndexType IndexType = VK_INDEX_TYPE_MAX_ENUM; @@ -633,7 +686,7 @@ public: private: StateCache m_State; VkCommandBuffer m_VkCmdBuffer = VK_NULL_HANDLE; - const VkPipelineStageFlags m_EnabledGraphicsShaderStages; + const VkPipelineStageFlags m_EnabledShaderStages; }; } // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp index 5e60a343..f68d7138 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp @@ -219,8 +219,9 @@ public: dataSize, pData, stride, flags); } - VkPipelineStageFlags GetEnabledGraphicsShaderStages() const { return m_EnabledGraphicsShaderStages; } - VkResult GetRayTracingShaderGroupHandles(VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData) const; + VkResult GetRayTracingShaderGroupHandles(VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData) const; + + VkPipelineStageFlags GetEnabledShaderStages() const { return m_EnabledShaderStages; } const VkPhysicalDeviceFeatures& GetEnabledFeatures() const { return m_EnabledFeatures; } const ExtensionFeatures& GetEnabledExtFeatures() const { return m_EnabledExtFeatures; } @@ -242,7 +243,7 @@ private: VkDevice m_VkDevice = VK_NULL_HANDLE; const VkAllocationCallbacks* const m_VkAllocator; - VkPipelineStageFlags m_EnabledGraphicsShaderStages = 0; + VkPipelineStageFlags m_EnabledShaderStages = 0; const VkPhysicalDeviceFeatures m_EnabledFeatures; ExtensionFeatures m_EnabledExtFeatures = {}; }; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.hpp index 4ada51be..4d9eaa7f 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.hpp @@ -95,10 +95,11 @@ struct VulkanMemoryAllocation class VulkanMemoryPage { public: - VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr, - VkDeviceSize PageSize, - uint32_t MemoryTypeIndex, - bool IsHostVisible) noexcept; + VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr, + VkDeviceSize PageSize, + uint32_t MemoryTypeIndex, + bool IsHostVisible, + VkMemoryAllocateFlags AllocateFlags) noexcept; ~VulkanMemoryPage(); // clang-format off @@ -198,8 +199,8 @@ public: VulkanMemoryManager& operator= (VulkanMemoryManager&&) = delete; // clang-format on - VulkanMemoryAllocation Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible); - VulkanMemoryAllocation Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps); + VulkanMemoryAllocation Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible, VkMemoryAllocateFlags AllocateFlags); + VulkanMemoryAllocation Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps, VkMemoryAllocateFlags AllocateFlags); void ShrinkMemory(); protected: @@ -218,19 +219,23 @@ protected: std::mutex m_PagesMtx; struct MemoryPageIndex { - const uint32_t MemoryTypeIndex; - const bool IsHostVisible; + const uint32_t MemoryTypeIndex; + const VkMemoryAllocateFlags AllocateFlags; + const bool IsHostVisible; // clang-format off - MemoryPageIndex(uint32_t _MemoryTypeIndex, - bool _IsHostVisible) : - MemoryTypeIndex(_MemoryTypeIndex), - IsHostVisible (_IsHostVisible) + MemoryPageIndex(uint32_t _MemoryTypeIndex, + bool _IsHostVisible, + VkMemoryAllocateFlags _AllocateFlags) : + MemoryTypeIndex{_MemoryTypeIndex}, + AllocateFlags {_AllocateFlags}, + IsHostVisible {_IsHostVisible} {} bool operator == (const MemoryPageIndex& rhs)const { return MemoryTypeIndex == rhs.MemoryTypeIndex && + AllocateFlags == rhs.AllocateFlags && IsHostVisible == rhs.IsHostVisible; } // clang-format on @@ -239,7 +244,7 @@ protected: { size_t operator()(const MemoryPageIndex& PageIndex) const { - return Diligent::ComputeHash(PageIndex.MemoryTypeIndex, PageIndex.IsHostVisible); + return Diligent::ComputeHash(PageIndex.MemoryTypeIndex, PageIndex.AllocateFlags, PageIndex.IsHostVisible); } }; }; diff --git a/Graphics/GraphicsEngineVulkan/interface/BottomLevelASVk.h b/Graphics/GraphicsEngineVulkan/interface/BottomLevelASVk.h index 345b0f3b..ea785a51 100644 --- a/Graphics/GraphicsEngineVulkan/interface/BottomLevelASVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/BottomLevelASVk.h @@ -61,7 +61,8 @@ DILIGENT_END_INTERFACE #if DILIGENT_C_INTERFACE -# define IBottomLevelASVk_GetVkBLAS(This) CALL_IFACE_METHOD(BottomLevelASVk, GetVkBLAS, This) +# define IBottomLevelASVk_GetVkBLAS(This) CALL_IFACE_METHOD(BottomLevelASVk, GetVkBLAS, This) +# define IBottomLevelASVk_GetVkDeviceAddress(This) CALL_IFACE_METHOD(BottomLevelASVk, GetVkDeviceAddress, This) #endif diff --git a/Graphics/GraphicsEngineVulkan/interface/ShaderBindingTableVk.h b/Graphics/GraphicsEngineVulkan/interface/ShaderBindingTableVk.h index 76e0eadd..d879faac 100644 --- a/Graphics/GraphicsEngineVulkan/interface/ShaderBindingTableVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/ShaderBindingTableVk.h @@ -31,6 +31,7 @@ /// Definition of the Diligent::IShaderBindingTableVk interface #include "../../GraphicsEngine/interface/ShaderBindingTable.h" +#include "DeviceContextVk.h" DILIGENT_BEGIN_NAMESPACE(Diligent) @@ -51,10 +52,12 @@ DILIGENT_BEGIN_INTERFACE(IShaderBindingTableVk, IShaderBindingTable) { /// AZ TODO VIRTUAL void METHOD(GetVkStridedBufferRegions)(THIS_ - VkStridedBufferRegionKHR REF RaygenShaderBindingTable, - VkStridedBufferRegionKHR REF MissShaderBindingTable, - VkStridedBufferRegionKHR REF HitShaderBindingTable, - VkStridedBufferRegionKHR REF CallableShaderBindingTable) PURE; + IDeviceContextVk* pContext, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + VkStridedBufferRegionKHR REF RaygenShaderBindingTable, + VkStridedBufferRegionKHR REF MissShaderBindingTable, + VkStridedBufferRegionKHR REF HitShaderBindingTable, + VkStridedBufferRegionKHR REF CallableShaderBindingTable) PURE; }; DILIGENT_END_INTERFACE // clang-format on diff --git a/Graphics/GraphicsEngineVulkan/interface/TopLevelASVk.h b/Graphics/GraphicsEngineVulkan/interface/TopLevelASVk.h index c09f10c0..161de182 100644 --- a/Graphics/GraphicsEngineVulkan/interface/TopLevelASVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/TopLevelASVk.h @@ -50,9 +50,6 @@ DILIGENT_BEGIN_INTERFACE(ITopLevelASVk, ITopLevelAS) { /// Returns a Vulkan TLAS object handle. VIRTUAL VkAccelerationStructureKHR METHOD(GetVkTLAS)(THIS) CONST PURE; - - /// Returns a Vulkan TLAS device address. - VIRTUAL VkDeviceAddress METHOD(GetVkDeviceAddress)(THIS) CONST PURE; }; DILIGENT_END_INTERFACE @@ -60,8 +57,7 @@ DILIGENT_END_INTERFACE #if DILIGENT_C_INTERFACE -# define ITopLevelASVk_GetVkTLAS(This) CALL_IFACE_METHOD(TopLevelASVk, GetVkTLAS, This) -# define ITopLevelASVk_GetVkDeviceAddress(This) CALL_IFACE_METHOD(TopLevelASVk, GetVkDeviceAddress, This) +# define ITopLevelASVk_GetVkTLAS(This) CALL_IFACE_METHOD(TopLevelASVk, GetVkTLAS, This) #endif diff --git a/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp index 6e0bcbb8..a1172130 100644 --- a/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp @@ -60,7 +60,7 @@ BottomLevelASVkImpl::BottomLevelASVkImpl(IReferenceCounters* pRefCounters, if (m_Desc.pTriangles != nullptr) { Uint32 MaxPrimitiveCount = 0; - for (uint32_t i = 0; i < CreateInfo.maxGeometryCount; ++i) + for (uint32_t i = 0; i < m_Desc.TriangleCount; ++i) { auto& src = m_Desc.pTriangles[i]; auto& dst = Geometries[i]; @@ -81,7 +81,7 @@ BottomLevelASVkImpl::BottomLevelASVkImpl(IReferenceCounters* pRefCounters, else if (m_Desc.pBoxes != nullptr) { Uint32 MaxBoxCount = 0; - for (uint32_t i = 0; i < CreateInfo.maxGeometryCount; ++i) + for (uint32_t i = 0; i < m_Desc.BoxCount; ++i) { auto& src = m_Desc.pBoxes[i]; auto& dst = Geometries[i]; @@ -122,10 +122,12 @@ BottomLevelASVkImpl::BottomLevelASVkImpl(IReferenceCounters* pRefCounters, LOG_ERROR_AND_THROW("Failed to find suitable memory type for BLAS '", m_Desc.Name, '\''); VERIFY(IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!"); - m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex); + m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex); + m_MemoryAlignedOffset = Align(VkDeviceSize{m_MemoryAllocation.UnalignedOffset}, MemReqs.alignment); + VERIFY(m_MemoryAllocation.Size >= MemReqs.size + (m_MemoryAlignedOffset - m_MemoryAllocation.UnalignedOffset), "Size of memory allocation is too small"); auto Memory = m_MemoryAllocation.Page->GetVkMemory(); - auto err = LogicalDevice.BindASMemory(m_VulkanBLAS, Memory, 0); + auto err = LogicalDevice.BindASMemory(m_VulkanBLAS, Memory, m_MemoryAlignedOffset); CHECK_VK_ERROR_AND_THROW(err, "Failed to bind AS memory"); m_DeviceAddress = LogicalDevice.GetAccelerationStructureDeviceAddress(m_VulkanBLAS); diff --git a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp index 6b29af25..ef6685a3 100644 --- a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp @@ -87,7 +87,7 @@ BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | // The buffer can be used as the source of a transfer command VK_BUFFER_USAGE_TRANSFER_DST_BIT; // The buffer can be used as the destination of a transfer command - static_assert(BIND_FLAGS_LAST == 0x400, "AZ TODO"); + static_assert(BIND_FLAGS_LAST == 0x400, "Please update this function to handle the new bind flags"); for (Uint32 BindFlag = 1; BindFlag <= m_Desc.BindFlags; BindFlag <<= 1) { @@ -245,11 +245,15 @@ BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters, MemoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, vkMemoryFlags); } + VkMemoryAllocateFlags AllocateFlags = 0; + if (VkBuffCI.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) + AllocateFlags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; + if (MemoryTypeIndex == VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex) LOG_ERROR_AND_THROW("Failed to find suitable memory type for buffer '", m_Desc.Name, '\''); VERIFY(IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!"); - m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex); + m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, AllocateFlags); m_BufferMemoryAlignedOffset = Align(VkDeviceSize{m_MemoryAllocation.UnalignedOffset}, MemReqs.alignment); VERIFY(m_MemoryAllocation.Size >= MemReqs.size + (m_BufferMemoryAlignedOffset - m_MemoryAllocation.UnalignedOffset), "Size of memory allocation is too small"); @@ -317,12 +321,12 @@ BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters, VkCommandBuffer vkCmdBuff; pRenderDeviceVk->AllocateTransientCmdPool(CmdPool, vkCmdBuff, "Transient command pool to copy staging data to a device buffer"); - auto EnabledGraphicsShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages(); - VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT, EnabledGraphicsShaderStages); + auto EnabledShaderStages = LogicalDevice.GetEnabledShaderStages(); + VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT, EnabledShaderStages); InitialState = RESOURCE_STATE_COPY_DEST; VkAccessFlags AccessFlags = ResourceStateFlagsToVkAccessFlags(InitialState); VERIFY_EXPR(AccessFlags == VK_ACCESS_TRANSFER_WRITE_BIT); - VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, m_VulkanBuffer, 0, AccessFlags, EnabledGraphicsShaderStages); + VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, m_VulkanBuffer, 0, AccessFlags, EnabledShaderStages); // Copy commands MUST be recorded outside of a render pass instance. This is OK here // as copy will be the only command in the cmd buffer diff --git a/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp index e7fbc9bd..6d0e1ab2 100644 --- a/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp +++ b/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp @@ -53,14 +53,17 @@ VulkanUtilities::CommandPoolWrapper CommandPoolManager::AllocateCommandPool(cons { std::lock_guard LockGuard{m_Mutex}; + auto& LogicalDevice = m_DeviceVkImpl.GetLogicalDevice(); + VulkanUtilities::CommandPoolWrapper CmdPool; if (!m_CmdPools.empty()) { CmdPool = std::move(m_CmdPools.front()); m_CmdPools.pop_front(); + + LogicalDevice.ResetCommandPool(CmdPool); } - auto& LogicalDevice = m_DeviceVkImpl.GetLogicalDevice(); if (CmdPool == VK_NULL_HANDLE) { VkCommandPoolCreateInfo CmdPoolCI = {}; @@ -74,8 +77,6 @@ VulkanUtilities::CommandPoolWrapper CommandPoolManager::AllocateCommandPool(cons DEV_CHECK_ERR(CmdPool != VK_NULL_HANDLE, "Failed to create Vulkan command pool"); } - LogicalDevice.ResetCommandPool(CmdPool); - #ifdef DILIGENT_DEVELOPMENT ++m_AllocatedPoolCounter; #endif diff --git a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp index 412ddd7b..6557ac6d 100644 --- a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp @@ -59,6 +59,41 @@ VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::CreateDescriptorPo return m_DeviceVkImpl.GetLogicalDevice().CreateDescriptorPool(PoolCI, DebugName); } +DescriptorPoolManager::DescriptorPoolManager(RenderDeviceVkImpl& DeviceVkImpl, + std::string PoolName, + std::vector PoolSizes, + uint32_t MaxSets, + bool AllowFreeing) noexcept : + // clang-format off + m_DeviceVkImpl{DeviceVkImpl }, + m_PoolName {std::move(PoolName) }, + m_PoolSizes (std::move(PoolSizes)), + m_MaxSets {MaxSets }, + m_AllowFreeing{AllowFreeing } +// clang-format on +{ + const auto& Feats = m_DeviceVkImpl.GetLogicalDevice().GetEnabledExtFeatures(); + + for (auto iter = m_PoolSizes.begin(); iter != m_PoolSizes.end();) + { + switch (iter->type) + { + case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: + if (Feats.RayTracing.rayTracing == VK_FALSE) + iter = m_PoolSizes.erase(iter); + else + ++iter; + break; + default: + ++iter; + } + } + +#ifdef DILIGENT_DEVELOPMENT + m_AllocatedPoolCounter = 0; +#endif +} + DescriptorPoolManager::~DescriptorPoolManager() { DEV_CHECK_ERR(m_AllocatedPoolCounter == 0, "Not all allocated descriptor pools are returned to the pool manager"); diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 42f69dac..554352ad 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -36,9 +36,6 @@ #include "VulkanTypeConversions.hpp" #include "CommandListVkImpl.hpp" #include "FenceVkImpl.hpp" -#include "BottomLevelASVkImpl.hpp" -#include "TopLevelASVkImpl.hpp" -#include "ShaderBindingTableVkImpl.hpp" #include "GraphicsAccessories.hpp" namespace Diligent @@ -72,7 +69,7 @@ DeviceContextVkImpl::DeviceContextVkImpl(IReferenceCounters* p bIsDeferred ? std::numeric_limits::max() : EngineCI.NumCommandsToFlushCmdBuffer, bIsDeferred }, - m_CommandBuffer { pDeviceVkImpl->GetLogicalDevice().GetEnabledGraphicsShaderStages() }, + m_CommandBuffer { pDeviceVkImpl->GetLogicalDevice().GetEnabledShaderStages() }, m_CmdListAllocator { GetRawAllocator(), sizeof(CommandListVkImpl), 64 }, // Command pools must be thread safe because command buffers are returned into pools by release queues // potentially running in another thread @@ -303,7 +300,7 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState) } case PIPELINE_TYPE_RAY_TRACING: { - //m_CommandBuffer.BindRayTracingPipeline(vkPipeline); + m_CommandBuffer.BindRayTracingPipeline(vkPipeline); break; } default: @@ -659,6 +656,19 @@ void DeviceContextVkImpl::PrepareForDispatchCompute() #endif } +void DeviceContextVkImpl::PrepareForRayTracing() +{ + EnsureVkCmdBuffer(); + + if (m_DescrSetBindInfo.DynamicOffsetCount != 0) + { + if (!m_DescrSetBindInfo.DynamicDescriptorsBound || m_DescrSetBindInfo.DynamicBuffersPresent) + { + m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, m_DescrSetBindInfo); + } + } +} + void DeviceContextVkImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) { if (!DvpVerifyDispatchArguments(Attribs)) @@ -2390,7 +2400,9 @@ void DeviceContextVkImpl::TransitionTextureState(TextureVkImpl& Textur // to make sure that all UAV writes are complete and visible. auto OldLayout = ResourceStateToVkImageLayout(OldState); auto NewLayout = ResourceStateToVkImageLayout(NewState); - m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, *pSubresRange); + auto OldStages = ResourceStateFlagsToVkPipelineStageFlags(OldState, m_CommandBuffer.GetEnabledShaderStages()); + auto NewStages = ResourceStateFlagsToVkPipelineStageFlags(NewState, m_CommandBuffer.GetEnabledShaderStages()); + m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, *pSubresRange, OldStages, NewStages); if (UpdateTextureState) { TextureVk.SetState(NewState); @@ -2479,7 +2491,7 @@ void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE // 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 (((OldState & NewState) != NewState) || NewState == RESOURCE_STATE_UNORDERED_ACCESS) + if (((OldState & NewState) != NewState) || NewState == RESOURCE_STATE_UNORDERED_ACCESS || NewState == RESOURCE_STATE_BUILD_AS_WRITE) { DEV_CHECK_ERR(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer"); VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0); @@ -2488,7 +2500,9 @@ void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE auto vkBuff = BufferVk.GetVkBuffer(); auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState); - m_CommandBuffer.BufferMemoryBarrier(vkBuff, OldAccessFlags, NewAccessFlags); + auto OldStages = ResourceStateFlagsToVkPipelineStageFlags(OldState, m_CommandBuffer.GetEnabledShaderStages()); + auto NewStages = ResourceStateFlagsToVkPipelineStageFlags(NewState, m_CommandBuffer.GetEnabledShaderStages()); + m_CommandBuffer.BufferMemoryBarrier(vkBuff, OldAccessFlags, NewAccessFlags, OldStages, NewStages); if (UpdateBufferState) { BufferVk.SetState(NewState); @@ -2522,6 +2536,142 @@ void DeviceContextVkImpl::TransitionOrVerifyBufferState(BufferVkImpl& #endif } +void DeviceContextVkImpl::TransitionBLASState(BottomLevelASVkImpl& BLAS, + RESOURCE_STATE OldState, + RESOURCE_STATE NewState, + bool UpdateInternalState) +{ + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); + if (OldState == RESOURCE_STATE_UNKNOWN) + { + if (BLAS.IsInKnownState()) + { + OldState = BLAS.GetState(); + } + else + { + LOG_ERROR_MESSAGE("Failed to transition the state of BLAS '", BLAS.GetDesc().Name, "' because the BLAS state is unknown and is not explicitly specified"); + return; + } + } + else + { + if (BLAS.IsInKnownState() && BLAS.GetState() != OldState) + { + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(BLAS.GetState()), " of BLAS '", + BLAS.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + " specified by the barrier"); + } + } + + if ((OldState & NewState) != NewState) + { + EnsureVkCmdBuffer(); + auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); + auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState); + auto OldStages = ResourceStateFlagsToVkPipelineStageFlags(OldState, m_CommandBuffer.GetEnabledShaderStages()); + auto NewStages = ResourceStateFlagsToVkPipelineStageFlags(NewState, m_CommandBuffer.GetEnabledShaderStages()); + m_CommandBuffer.ASMemoryBarrier(OldAccessFlags, NewAccessFlags, OldStages, NewStages); + if (UpdateInternalState) + { + BLAS.SetState(NewState); + } + } +} + +void DeviceContextVkImpl::TransitionTLASState(TopLevelASVkImpl& TLAS, + RESOURCE_STATE OldState, + RESOURCE_STATE NewState, + bool UpdateInternalState) +{ + // AZ TODO: transit BLAS state too? + + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); + if (OldState == RESOURCE_STATE_UNKNOWN) + { + if (TLAS.IsInKnownState()) + { + OldState = TLAS.GetState(); + } + else + { + LOG_ERROR_MESSAGE("Failed to transition the state of TLAS '", TLAS.GetDesc().Name, "' because the TLAS state is unknown and is not explicitly specified"); + return; + } + } + else + { + if (TLAS.IsInKnownState() && TLAS.GetState() != OldState) + { + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(TLAS.GetState()), " of TLAS '", + TLAS.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + " specified by the barrier"); + } + } + + if ((OldState & NewState) != NewState) + { + EnsureVkCmdBuffer(); + auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); + auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState); + auto OldStages = ResourceStateFlagsToVkPipelineStageFlags(OldState, m_CommandBuffer.GetEnabledShaderStages()); + auto NewStages = ResourceStateFlagsToVkPipelineStageFlags(NewState, m_CommandBuffer.GetEnabledShaderStages()); + m_CommandBuffer.ASMemoryBarrier(OldAccessFlags, NewAccessFlags, OldStages, NewStages); + if (UpdateInternalState) + { + TLAS.SetState(NewState); + } + } +} + +void DeviceContextVkImpl::TransitionOrVerifyBLASState(BottomLevelASVkImpl& BLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName) +{ + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); + if (BLAS.IsInKnownState()) + { + if (!BLAS.CheckState(RequiredState)) + { + TransitionBLASState(BLAS, RESOURCE_STATE_UNKNOWN, RequiredState, true); + } + } + } +#ifdef DILIGENT_DEVELOPMENT + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + DvpVerifyBLASState(BLAS, RequiredState, OperationName); + } +#endif +} + +void DeviceContextVkImpl::TransitionOrVerifyTLASState(TopLevelASVkImpl& TLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName) +{ + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); + if (TLAS.IsInKnownState()) + { + if (!TLAS.CheckState(RequiredState)) + { + TransitionTLASState(TLAS, RESOURCE_STATE_UNKNOWN, RequiredState, true); + } + } + } +#ifdef DILIGENT_DEVELOPMENT + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + DvpVerifyTLASState(TLAS, RequiredState, OperationName); + } +#endif +} + VulkanDynamicAllocation DeviceContextVkImpl::AllocateDynamicSpace(Uint32 SizeInBytes, Uint32 Alignment) { auto DynAlloc = m_DynamicHeap.Allocate(SizeInBytes, Alignment); @@ -2554,24 +2704,27 @@ void DeviceContextVkImpl::TransitionResourceStates(Uint32 BarrierCount, StateTra } VERIFY(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END, "Unexpected barrier type"); - if (Barrier.pTexture) + RefCntAutoPtr pTexture{Barrier.pResource, IID_TextureVk}; + if (pTexture) { - auto* pTextureVkImpl = ValidatedCast(Barrier.pTexture); - VkImageSubresourceRange SubResRange; SubResRange.aspectMask = 0; SubResRange.baseMipLevel = Barrier.FirstMipLevel; SubResRange.levelCount = (Barrier.MipLevelsCount == REMAINING_MIP_LEVELS) ? VK_REMAINING_MIP_LEVELS : Barrier.MipLevelsCount; SubResRange.baseArrayLayer = Barrier.FirstArraySlice; SubResRange.layerCount = (Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES) ? VK_REMAINING_ARRAY_LAYERS : Barrier.ArraySliceCount; - TransitionTextureState(*pTextureVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState, &SubResRange); + TransitionTextureState(*pTexture, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState, &SubResRange); + continue; } - else + + RefCntAutoPtr pBuffer{Barrier.pResource, IID_BufferVk}; + if (pBuffer) { - VERIFY_EXPR(Barrier.pBuffer != nullptr); - auto* pBufferVkImpl = ValidatedCast(Barrier.pBuffer); - TransitionBufferState(*pBufferVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); + TransitionBufferState(*pBuffer, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); + continue; } + + UNEXPECTED("unsupported resource type"); } } @@ -2635,13 +2788,10 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) if (!TDeviceContextBase::BuildBLAS(Attribs, 0)) return; - - // AZ TODO: transitions - #ifdef DILIGENT_DEBUG { - const auto& PhysicalDevice = m_pDevice->GetPhysicalDevice(); - VERIFY_EXPR(PhysicalDevice.GetExtFeatures().RayTracing.rayTracing != VK_FALSE); + const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); + VERIFY_EXPR(LogicalDevice.GetEnabledExtFeatures().RayTracing.rayTracing != VK_FALSE); } #endif @@ -2649,6 +2799,12 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) auto* pScratchVk = ValidatedCast(Attribs.pScratchBuffer); auto& BLASDesc = pBLASVk->GetDesc(); + EnsureVkCmdBuffer(); + + const char* OpName = "Build BottomLevelAS (DeviceContextVkImpl::BuildBLAS)"; + TransitionOrVerifyBLASState(*pBLASVk, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + TransitionOrVerifyBufferState(*pScratchVk, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, VkAccessFlagBits(0), OpName); + VkAccelerationStructureBuildGeometryInfoKHR Info = {}; std::vector Offsets; std::vector Geometries; @@ -2679,17 +2835,21 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) tri.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; tri.pNext = nullptr; - auto* pVB = ValidatedCast(src.pVertexBuffer); + auto* pVB = ValidatedCast(src.pVertexBuffer); tri.vertexFormat = TypeToVkFormat(src.VertexValueType, src.VertexComponentCount, src.VertexValueType < VT_FLOAT16); tri.vertexStride = src.VertexStride; tri.vertexData.deviceAddress = pVB->GetVkDeviceAddress() + src.VertexOffset; + TransitionOrVerifyBufferState(*pVB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VkAccessFlagBits(0), OpName); + if (src.pIndexBuffer) { - auto* pIB = ValidatedCast(src.pIndexBuffer); + auto* pIB = ValidatedCast(src.pIndexBuffer); tri.indexType = TypeToVkIndexType(src.IndexType); tri.indexData.deviceAddress = pIB->GetVkDeviceAddress() + src.IndexOffset; off.primitiveCount = src.IndexCount / 3; + + TransitionOrVerifyBufferState(*pIB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VkAccessFlagBits(0), OpName); } else { @@ -2700,11 +2860,18 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) if (src.pTransformBuffer) { - auto* pTB = ValidatedCast(src.pTransformBuffer); + VERIFY_EXPR(BLASDesc.pTriangles[j].AllowsTransforms); + + auto* pTB = ValidatedCast(src.pTransformBuffer); tri.transformData.deviceAddress = pTB->GetVkDeviceAddress() + src.TransformBufferOffset; + + TransitionOrVerifyBufferState(*pTB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VkAccessFlagBits(0), OpName); } else + { + VERIFY_EXPR(!BLASDesc.pTriangles[j].AllowsTransforms); tri.transformData.deviceAddress = 0; + } off.firstVertex = 0; off.primitiveOffset = 0; @@ -2730,22 +2897,25 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) continue; } - auto* pBB = ValidatedCast(src.pBoxBuffer); + dst.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + dst.pNext = nullptr; + dst.flags = GeometryFlagsToVkGeometryFlags(src.Flags); + dst.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + + auto* pBB = ValidatedCast(src.pBoxBuffer); box.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; box.pNext = nullptr; box.stride = src.BoxStride; box.data.deviceAddress = pBB->GetVkDeviceAddress() + src.BoxOffset; + TransitionOrVerifyBufferState(*pBB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VkAccessFlagBits(0), OpName); + off.firstVertex = 0; off.transformOffset = 0; off.primitiveOffset = 0; off.primitiveCount = src.BoxCount; } } - else - { - UNEXPECTED("pTriangleData or pBoxData must not be null"); - } VkAccelerationStructureGeometryKHR const* GeometriesPtr = Geometries.data(); VkAccelerationStructureBuildOffsetInfoKHR const* OffsetsPtr = Offsets.data(); @@ -2763,6 +2933,7 @@ void DeviceContextVkImpl::BuildBLAS(const BLASBuildAttribs& Attribs) EnsureVkCmdBuffer(); m_CommandBuffer.BuildAccelerationStructure(1, &Info, &OffsetsPtr); + ++m_State.NumCommands; } void DeviceContextVkImpl::BuildTLAS(const TLASBuildAttribs& Attribs) @@ -2770,23 +2941,27 @@ void DeviceContextVkImpl::BuildTLAS(const TLASBuildAttribs& Attribs) if (!TDeviceContextBase::BuildTLAS(Attribs, 0)) return; - static_assert(TLASInstanceDataSize == sizeof(VkAccelerationStructureInstanceKHR), "AZ TODO"); - - // AZ TODO: transitions + static_assert(TLAS_INSTANCE_DATA_SIZE == sizeof(VkAccelerationStructureInstanceKHR), "Value in TLAS_INSTANCE_DATA_SIZE doesn't match the actual instance description size"); #ifdef DILIGENT_DEBUG { - const auto& PhysicalDevice = m_pDevice->GetPhysicalDevice(); - VERIFY_EXPR(PhysicalDevice.GetExtFeatures().RayTracing.rayTracing != VK_FALSE); + const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); + VERIFY_EXPR(LogicalDevice.GetEnabledExtFeatures().RayTracing.rayTracing != VK_FALSE); } #endif auto* pTLASVk = ValidatedCast(Attribs.pTLAS); auto* pScratchVk = ValidatedCast(Attribs.pScratchBuffer); - auto* pInstancesVk = ValidatedCast(Attribs.pInstancesBuffer); + auto* pInstancesVk = ValidatedCast(Attribs.pInstanceBuffer); auto& TLASDesc = pTLASVk->GetDesc(); - pTLASVk->SetInstanceData(Attribs.pInstances, Attribs.InstanceCount); + EnsureVkCmdBuffer(); + + const char* OpName = "Build TopLevelAS (DeviceContextVkImpl::BuildTLAS)"; + TransitionOrVerifyTLASState(*pTLASVk, Attribs.TLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + TransitionOrVerifyBufferState(*pScratchVk, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, VkAccessFlagBits(0), OpName); + + pTLASVk->SetInstanceData(Attribs.pInstances, Attribs.InstanceCount, Attribs.HitShadersPerInstance); // copy instance data into instance buffer { @@ -2798,34 +2973,42 @@ void DeviceContextVkImpl::BuildTLAS(const TLASBuildAttribs& Attribs) { auto& src = Attribs.pInstances[i]; auto& dst = static_cast(pMappedInstances)[i]; - auto* pBLASVk = ValidatedCast(src.pBLAS); + auto* pBLASVk = ValidatedCast(src.pBLAS); static_assert(sizeof(dst.transform) == sizeof(src.Transform), "size mismatch"); std::memcpy(&dst.transform, src.Transform, sizeof(dst.transform)); - dst.instanceCustomIndex = src.customId; - dst.instanceShaderBindingTableRecordOffset = src.contributionToHitGroupIndex; + dst.instanceCustomIndex = src.CustomId; + dst.instanceShaderBindingTableRecordOffset = pTLASVk->GetInstanceDesc(src.InstanceName).ContributionToHitGroupIndex; // AZ TODO: optimize dst.mask = src.Mask; dst.flags = InstanceFlagsToVkGeometryInstanceFlags(src.Flags); dst.accelerationStructureReference = pBLASVk->GetVkDeviceAddress(); + + TransitionOrVerifyBLASState(*pBLASVk, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); } - UpdateBufferRegion(pInstancesVk, Attribs.InstancesBufferOffset, Size, TmpSpace.vkBuffer, TmpSpace.AlignedOffset, Attribs.InstanceBufferTransitionMode); + UpdateBufferRegion(pInstancesVk, Attribs.InstanceBufferOffset, Size, TmpSpace.vkBuffer, TmpSpace.AlignedOffset, Attribs.InstanceBufferTransitionMode); } + TransitionOrVerifyBufferState(*pInstancesVk, Attribs.InstanceBufferTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VkAccessFlagBits(0), OpName); VkAccelerationStructureBuildGeometryInfoKHR Info = {}; VkAccelerationStructureBuildOffsetInfoKHR Offset = {}; VkAccelerationStructureBuildOffsetInfoKHR const* OffsetsPtr = &Offset; - VkAccelerationStructureGeometryKHR Geometry = {VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + VkAccelerationStructureGeometryKHR Geometry = {}; VkAccelerationStructureGeometryKHR const* GeometriesPtr = &Geometry; Offset.primitiveCount = Attribs.InstanceCount; - Geometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + Geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + Geometry.pNext = nullptr; + Geometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + Geometry.flags = 0; + auto& inst = Geometry.geometry.instances; inst.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + inst.pNext = nullptr; inst.arrayOfPointers = VK_FALSE; - inst.data.deviceAddress = pInstancesVk->GetVkDeviceAddress() + Attribs.InstancesBufferOffset; + inst.data.deviceAddress = pInstancesVk->GetVkDeviceAddress() + Attribs.InstanceBufferOffset; Info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; Info.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; // type must be compatible with create info @@ -2838,8 +3021,8 @@ void DeviceContextVkImpl::BuildTLAS(const TLASBuildAttribs& Attribs) Info.ppGeometries = &GeometriesPtr; Info.scratchData.deviceAddress = pScratchVk->GetVkDeviceAddress() + Attribs.ScratchBufferOffset; - EnsureVkCmdBuffer(); m_CommandBuffer.BuildAccelerationStructure(1, &Info, &OffsetsPtr); + ++m_State.NumCommands; } void DeviceContextVkImpl::CopyBLAS(const CopyBLASAttribs& Attribs) @@ -2847,12 +3030,10 @@ void DeviceContextVkImpl::CopyBLAS(const CopyBLASAttribs& Attribs) if (!TDeviceContextBase::CopyBLAS(Attribs, 0)) return; - // AZ TODO: transitions - #ifdef DILIGENT_DEBUG { - const auto& PhysicalDevice = m_pDevice->GetPhysicalDevice(); - VERIFY_EXPR(PhysicalDevice.GetExtFeatures().RayTracing.rayTracing != VK_FALSE); + const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); + VERIFY_EXPR(LogicalDevice.GetEnabledExtFeatures().RayTracing.rayTracing != VK_FALSE); } #endif @@ -2867,7 +3048,13 @@ void DeviceContextVkImpl::CopyBLAS(const CopyBLASAttribs& Attribs) Info.mode = CopyASModeToVkCopyAccelerationStructureMode(Attribs.Mode); EnsureVkCmdBuffer(); + + const char* OpName = "Copy BottomLevelAS (DeviceContextVkImpl::CopyBLAS)"; + TransitionOrVerifyBLASState(*pSrcVk, Attribs.TransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyBLASState(*pDstVk, Attribs.TransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + m_CommandBuffer.CopyAccelerationStructure(Info); + ++m_State.NumCommands; } void DeviceContextVkImpl::CopyTLAS(const CopyTLASAttribs& Attribs) @@ -2875,11 +3062,11 @@ void DeviceContextVkImpl::CopyTLAS(const CopyTLASAttribs& Attribs) if (!TDeviceContextBase::CopyTLAS(Attribs, 0)) return; - // AZ TODO: transitions - #ifdef DILIGENT_DEBUG - auto& PhysicalDevice = m_pDevice->GetPhysicalDevice(); - VERIFY_EXPR(PhysicalDevice.GetExtFeatures().RayTracing.rayTracing == VK_TRUE); + { + const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); + VERIFY_EXPR(LogicalDevice.GetEnabledExtFeatures().RayTracing.rayTracing != VK_FALSE); + } #endif auto* pSrcVk = ValidatedCast(Attribs.pSrc); @@ -2893,7 +3080,13 @@ void DeviceContextVkImpl::CopyTLAS(const CopyTLASAttribs& Attribs) Info.mode = CopyASModeToVkCopyAccelerationStructureMode(Attribs.Mode); EnsureVkCmdBuffer(); + + const char* OpName = "Copy TopLevelAS (DeviceContextVkImpl::CopyTLAS)"; + TransitionOrVerifyTLASState(*pSrcVk, Attribs.TransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyTLASState(*pDstVk, Attribs.TransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + m_CommandBuffer.CopyAccelerationStructure(Info); + ++m_State.NumCommands; } void DeviceContextVkImpl::TraceRays(const TraceRaysAttribs& Attribs) @@ -2901,12 +3094,10 @@ void DeviceContextVkImpl::TraceRays(const TraceRaysAttribs& Attribs) if (!TDeviceContextBase::TraceRays(Attribs, 0)) return; - // AZ TODO: transitions - #ifdef DILIGENT_DEBUG { - const auto& PhysicalDevice = m_pDevice->GetPhysicalDevice(); - VERIFY_EXPR(PhysicalDevice.GetExtFeatures().RayTracing.rayTracing == VK_TRUE); + const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); + VERIFY_EXPR(LogicalDevice.GetEnabledExtFeatures().RayTracing.rayTracing != VK_FALSE); } #endif @@ -2916,12 +3107,12 @@ void DeviceContextVkImpl::TraceRays(const TraceRaysAttribs& Attribs) VkStridedBufferRegionKHR CallableShaderBindingTable = {}; auto* pSBTVk = ValidatedCast(Attribs.pSBT); + pSBTVk->GetVkStridedBufferRegions(this, Attribs.TransitionMode, RaygenShaderBindingTable, MissShaderBindingTable, HitShaderBindingTable, CallableShaderBindingTable); - pSBTVk->GetVkStridedBufferRegions(RaygenShaderBindingTable, MissShaderBindingTable, HitShaderBindingTable, CallableShaderBindingTable); - - EnsureVkCmdBuffer(); + PrepareForRayTracing(); m_CommandBuffer.TraceRays(RaygenShaderBindingTable, MissShaderBindingTable, HitShaderBindingTable, CallableShaderBindingTable, Attribs.DimensionX, Attribs.DimensionY, Attribs.DimensionZ); + ++m_State.NumCommands; } } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 8aaee7f7..548a9cf3 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -390,24 +390,32 @@ void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& #define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ray tracing PSO '", CreateInfo.PSODesc.Name, "' is invalid: ", ##__VA_ARGS__) ShaderGroups.reserve(CreateInfo.GeneralShaderCount + CreateInfo.TriangleHitShaderCount + CreateInfo.ProceduralHitShaderCount); - Uint32 GroupIndex = 0; - Uint32 ShaderIndex = 0; + Uint32 GroupIndex = 0; + std::array ShaderIndices = {}; std::unordered_map UniqueShaders; - const auto ShaderToIndex = [&ShaderIndex, &UniqueShaders](const IShader* pShader) -> Uint32 { + const auto ShaderToIndex = [&ShaderIndices, &UniqueShaders](const IShader* pShader) -> Uint32 { if (pShader != nullptr) { - auto Result = UniqueShaders.emplace(pShader, ShaderIndex); + Uint32& Index = ShaderIndices[GetShaderTypePipelineIndex(pShader->GetDesc().ShaderType, PIPELINE_TYPE_RAY_TRACING)]; + auto Result = UniqueShaders.emplace(pShader, Index); if (Result.second) { - ++ShaderIndex; + ++Index; } return Result.first->second; } return VK_SHADER_UNUSED_KHR; }; + Uint32 ShaderCount = 0; + for (auto& Stage : ShaderStages) + { + ShaderIndices[GetShaderTypePipelineIndex(Stage.Type, PIPELINE_TYPE_RAY_TRACING)] = ShaderCount; + ShaderCount += static_cast(Stage.Count()); + } + for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i) { const auto& GeneralShader = CreateInfo.pGeneralShaders[i]; @@ -485,7 +493,7 @@ void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& ++ShaderIndex2; } } - VERIFY_EXPR(ShaderIndex == ShaderIndex2); + VERIFY_EXPR(UniqueShaders.size() == ShaderIndex2); #endif #undef LOG_PSO_ERROR_AND_THROW } diff --git a/Graphics/GraphicsEngineVulkan/src/QueryManagerVk.cpp b/Graphics/GraphicsEngineVulkan/src/QueryManagerVk.cpp index fb09687b..ec94814e 100644 --- a/Graphics/GraphicsEngineVulkan/src/QueryManagerVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/QueryManagerVk.cpp @@ -97,7 +97,7 @@ QueryManagerVk::QueryManagerVk(RenderDeviceVkImpl* pRenderDeviceVk, VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT; - const auto EnabledShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages(); + const auto EnabledShaderStages = LogicalDevice.GetEnabledShaderStages(); if (EnabledShaderStages & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT) { QueryPoolCI.pipelineStatistics |= diff --git a/Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp index 381ee631..a0801cb7 100644 --- a/Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp @@ -225,7 +225,7 @@ bool QueryVkImpl::GetData(void* pData, Uint32 DataSize, bool AutoInvalidate) { auto& QueryData = *reinterpret_cast(pData); - const auto EnabledShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages(); + const auto EnabledShaderStages = LogicalDevice.GetEnabledShaderStages(); auto Idx = 0; diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp index 36fa5af0..6f5091e0 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp @@ -27,6 +27,7 @@ #include "pch.h" #include "ShaderBindingTableVkImpl.hpp" +#include "BufferVkImpl.hpp" #include "VulkanTypeConversions.hpp" namespace Diligent @@ -40,10 +41,8 @@ ShaderBindingTableVkImpl::ShaderBindingTableVkImpl(IReferenceCounters* { ValidateDesc(Desc); - const auto& Props = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing; - - m_ShaderGroupHandleSize = Props.shaderGroupHandleSize; - m_ShaderGroupBaseAlignment = Props.shaderGroupBaseAlignment; + const auto& RTLimits = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing; + m_ShaderRecordStride = m_Desc.ShaderRecordSize + RTLimits.shaderGroupHandleSize; } ShaderBindingTableVkImpl::~ShaderBindingTableVkImpl() @@ -52,12 +51,12 @@ ShaderBindingTableVkImpl::~ShaderBindingTableVkImpl() void ShaderBindingTableVkImpl::ValidateDesc(const ShaderBindingTableDesc& Desc) const { - const auto& Props = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing; + const auto& RTLimits = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing; - if (Desc.ShaderRecordSize + Props.shaderGroupHandleSize > Props.maxShaderGroupStride) + if (Desc.ShaderRecordSize + RTLimits.shaderGroupHandleSize > RTLimits.maxShaderGroupStride) { LOG_ERROR_AND_THROW("Description of Shader binding table '", (Desc.Name ? Desc.Name : ""), - "' is invalid: ShaderRecordSize is too big, max size is: ", Props.maxShaderGroupStride - Props.shaderGroupHandleSize); + "' is invalid: ShaderRecordSize is too big, max size is: ", RTLimits.maxShaderGroupStride - RTLimits.shaderGroupHandleSize); } } @@ -68,6 +67,12 @@ void ShaderBindingTableVkImpl::Verify() const void ShaderBindingTableVkImpl::Reset(const ShaderBindingTableDesc& Desc) { + m_RayGenShaderRecord.clear(); + m_MissShadersRecord.clear(); + m_CallableShadersRecord.clear(); + m_HitGroupsRecord.clear(); + m_Changed = true; + try { ValidateShaderBindingTableDesc(Desc); @@ -75,116 +80,130 @@ void ShaderBindingTableVkImpl::Reset(const ShaderBindingTableDesc& Desc) } catch (const std::runtime_error&) { + // AZ TODO return; } m_Desc = Desc; - // free memory - decltype(m_ShaderRecords) temp{}; - std::swap(temp, m_ShaderRecords); - - m_MissShadersOffset = 0; - m_HitGroupsOffset = 0; - m_CallbaleShadersOffset = 0; - m_MissShaderCount = 0; - m_HitGroupCount = 0; - m_CallableShaderCount = 0; + const auto& RTLimits = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing; + m_ShaderRecordStride = m_Desc.ShaderRecordSize + RTLimits.shaderGroupHandleSize; } void ShaderBindingTableVkImpl::ResetHitGroups(Uint32 HitShadersPerInstance) { // AZ TODO -} -void ShaderBindingTableVkImpl::BindRayGenShader(const char* ShaderGroupName, const void* Data, Uint32 DataSize) -{ - // AZ TODO + m_Changed = true; } -void ShaderBindingTableVkImpl::BindMissShader(const char* ShaderGroupName, Uint32 MissIndex, const void* Data, Uint32 DataSize) +void ShaderBindingTableVkImpl::BindAll(const BindAllAttribs& Attribs) { // AZ TODO } -void ShaderBindingTableVkImpl::BindHitGroup(ITopLevelAS* pTLAS, - const char* InstanceName, - const char* GeometryName, - Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data, - Uint32 DataSize) +void ShaderBindingTableVkImpl::GetVkStridedBufferRegions(IDeviceContextVk* pContext, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + VkStridedBufferRegionKHR& RaygenShaderBindingTable, + VkStridedBufferRegionKHR& MissShaderBindingTable, + VkStridedBufferRegionKHR& HitShaderBindingTable, + VkStridedBufferRegionKHR& CallableShaderBindingTable) { - // AZ TODO -} + const auto ShaderGroupBaseAlignment = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing.shaderGroupBaseAlignment; -void ShaderBindingTableVkImpl::BindHitGroups(ITopLevelAS* pTLAS, - const char* InstanceName, - Uint32 RayOffsetInHitGroupIndex, - const char* ShaderGroupName, - const void* Data, - Uint32 DataSize) -{ - // AZ TODO -} + const auto AlignToLarger = [ShaderGroupBaseAlignment](size_t offset) -> Uint32 { + return Align(static_cast(offset), ShaderGroupBaseAlignment); + }; -void ShaderBindingTableVkImpl::BindCallableShader(Uint32 Index, - const char* ShaderName, - const void* Data, - Uint32 DataSize) -{ - // AZ TODO -} + const Uint32 RayGenOffset = 0; + const Uint32 MissShaderOffset = AlignToLarger(m_RayGenShaderRecord.size()); + const Uint32 HitGroupOffset = AlignToLarger(MissShaderOffset + m_MissShadersRecord.size()); + const Uint32 CallableShadersOffset = AlignToLarger(HitGroupOffset + m_HitGroupsRecord.size()); + const Uint32 BufSize = AlignToLarger(CallableShadersOffset + m_CallableShadersRecord.size()); -void ShaderBindingTableVkImpl::BindAll(const BindAllAttribs& Attribs) -{ - // AZ TODO -} + // recreate buffer + if (m_pBuffer == nullptr || m_pBuffer->GetDesc().uiSizeInBytes < BufSize) + { + m_pBuffer = nullptr; -void ShaderBindingTableVkImpl::GetVkStridedBufferRegions(VkStridedBufferRegionKHR& RaygenShaderBindingTable, - VkStridedBufferRegionKHR& MissShaderBindingTable, - VkStridedBufferRegionKHR& HitShaderBindingTable, - VkStridedBufferRegionKHR& CallableShaderBindingTable) -{ - const auto& Props = GetDevice()->GetPhysicalDevice().GetExtProperties().RayTracing; + String BuffName = String{GetDesc().Name} + " - internal buffer"; + BufferDesc BuffDesc; + BuffDesc.Name = BuffName.c_str(); + BuffDesc.Usage = USAGE_DEFAULT; + BuffDesc.BindFlags = BIND_RAY_TRACING; + BuffDesc.uiSizeInBytes = BufSize; + + GetDevice()->CreateBuffer(BuffDesc, nullptr, &m_pBuffer); + VERIFY_EXPR(m_pBuffer != nullptr); + } + + if (m_pBuffer == nullptr) + return; // something goes wrong - const VkDeviceSize Stride = m_Desc.ShaderRecordSize + Props.shaderGroupHandleSize; - VERIFY_EXPR(Stride <= Props.maxShaderGroupStride); + VkBuffer BuffHandle = m_pBuffer.RawPtr()->GetVkBuffer(); - RaygenShaderBindingTable.buffer = m_pBuffer->GetVkBuffer(); - RaygenShaderBindingTable.offset = 0; - RaygenShaderBindingTable.size = Stride; - RaygenShaderBindingTable.stride = Stride; + if (m_RayGenShaderRecord.size()) + { + RaygenShaderBindingTable.buffer = BuffHandle; + RaygenShaderBindingTable.offset = RayGenOffset; + RaygenShaderBindingTable.size = m_RayGenShaderRecord.size(); + RaygenShaderBindingTable.stride = m_ShaderRecordStride; + } + + if (m_MissShadersRecord.size()) + { + MissShaderBindingTable.buffer = BuffHandle; + MissShaderBindingTable.offset = MissShaderOffset; + MissShaderBindingTable.size = m_MissShadersRecord.size(); + MissShaderBindingTable.stride = m_ShaderRecordStride; + } - if (m_MissShaderCount > 0) + if (m_HitGroupsRecord.size()) { - MissShaderBindingTable.buffer = m_pBuffer->GetVkBuffer(); - MissShaderBindingTable.offset = m_MissShadersOffset; - MissShaderBindingTable.size = Stride * m_MissShaderCount; - MissShaderBindingTable.stride = Stride; + HitShaderBindingTable.buffer = BuffHandle; + HitShaderBindingTable.offset = HitGroupOffset; + HitShaderBindingTable.size = m_HitGroupsRecord.size(); + HitShaderBindingTable.stride = m_ShaderRecordStride; } - else - MissShaderBindingTable = {}; - if (m_HitGroupCount > 0) + if (m_CallableShadersRecord.size()) { - HitShaderBindingTable.buffer = m_pBuffer->GetVkBuffer(); - HitShaderBindingTable.offset = m_HitGroupsOffset; - HitShaderBindingTable.size = Stride * m_HitGroupCount; - HitShaderBindingTable.stride = Stride; + CallableShaderBindingTable.buffer = BuffHandle; + CallableShaderBindingTable.offset = CallableShadersOffset; + CallableShaderBindingTable.size = m_CallableShadersRecord.size(); + CallableShaderBindingTable.stride = m_ShaderRecordStride; } - else - HitShaderBindingTable = {}; - if (m_CallableShaderCount > 0) + if (!m_Changed) + return; + + m_Changed = false; + + // update buffer data + if (m_RayGenShaderRecord.size()) + pContext->UpdateBuffer(m_pBuffer, RayGenOffset, static_cast(m_RayGenShaderRecord.size()), m_RayGenShaderRecord.data(), TransitionMode); + + if (m_MissShadersRecord.size()) + pContext->UpdateBuffer(m_pBuffer, MissShaderOffset, static_cast(m_MissShadersRecord.size()), m_MissShadersRecord.data(), TransitionMode); + + if (m_HitGroupsRecord.size()) + pContext->UpdateBuffer(m_pBuffer, HitGroupOffset, static_cast(m_HitGroupsRecord.size()), m_HitGroupsRecord.data(), TransitionMode); + + if (m_CallableShadersRecord.size()) + pContext->UpdateBuffer(m_pBuffer, CallableShadersOffset, static_cast(m_CallableShadersRecord.size()), m_CallableShadersRecord.data(), TransitionMode); + + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + StateTransitionDesc Barrier; + Barrier.pResource = m_pBuffer; + Barrier.NewState = RESOURCE_STATE_RAY_TRACING; + Barrier.UpdateResourceState = true; + pContext->TransitionResourceStates(1, &Barrier); + } + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) { - CallableShaderBindingTable.buffer = m_pBuffer->GetVkBuffer(); - CallableShaderBindingTable.offset = m_CallbaleShadersOffset; - CallableShaderBindingTable.size = Stride * m_CallableShaderCount; - CallableShaderBindingTable.stride = Stride; + VERIFY_EXPR(m_pBuffer->GetState() == RESOURCE_STATE_RAY_TRACING); } - else - CallableShaderBindingTable = {}; } } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp index 8a9da14e..8101fefc 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp @@ -33,6 +33,7 @@ #include "TextureViewVkImpl.hpp" #include "TextureVkImpl.hpp" #include "SamplerVkImpl.hpp" +#include "TopLevelASVkImpl.hpp" #include "VulkanTypeConversions.hpp" namespace Diligent @@ -323,31 +324,31 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure: { - //auto* pTLASVk = Res.pObject.RawPtr(); - //if (pTLASVk != nullptr && pTLASVk->IsInKnownState()) - //{ - // constexpr RESOURCE_STATE RequiredState = RESOURCE_STATE_RAY_TRACING; - // const bool IsInRequiredState = pTLASVk->CheckState(RequiredState); - // if (VerifyOnly) - // { - // if (!IsInRequiredState) - // { - // LOG_ERROR_MESSAGE("State of TLAS '", pTLASVk->GetDesc().Name, "' is incorrect. Required state: ", - // GetResourceStateString(RequiredState), ". Actual state: ", - // GetResourceStateString(pTLASVk->GetState()), - // ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - // "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state " - // "with IDeviceContext::TransitionResourceStates()."); - // } - // } - // else - // { - // if (!IsInRequiredState) - // { - // pCtxVkImpl->TransitionTLASState(*pTLASVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); - // } - // } - //} + auto* pTLASVk = Res.pObject.RawPtr(); + if (pTLASVk != nullptr && pTLASVk->IsInKnownState()) + { + constexpr RESOURCE_STATE RequiredState = RESOURCE_STATE_RAY_TRACING; + const bool IsInRequiredState = pTLASVk->CheckState(RequiredState); + if (VerifyOnly) + { + if (!IsInRequiredState) + { + LOG_ERROR_MESSAGE("State of TLAS '", pTLASVk->GetDesc().Name, "' is incorrect. Required state: ", + GetResourceStateString(RequiredState), ". Actual state: ", + GetResourceStateString(pTLASVk->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state " + "with IDeviceContext::TransitionResourceStates()."); + } + } + else + { + if (!IsInRequiredState) + { + pCtxVkImpl->TransitionTLASState(*pTLASVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + } + } + } } break; @@ -532,13 +533,13 @@ VkWriteDescriptorSetAccelerationStructureKHR ShaderResourceCacheVk::Resource::Ge VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration structure resource is expected"); DEV_CHECK_ERR(pObject != nullptr, "Unable to get acceleration structure write info: cached object is null"); - //auto* pTLASVk = pObject.RawPtr(); + auto* pTLASVk = pObject.RawPtr(); - VkWriteDescriptorSetAccelerationStructureKHR DescrAS = {}; - //DescrAS.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; - //DescrAS.pNext = nullptr; - //DescrAS.accelerationStructureCount = 1; - //DescrAS.pAccelerationStructures = pTLASVk->GetVkTLASPtr(); + VkWriteDescriptorSetAccelerationStructureKHR DescrAS; + DescrAS.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + DescrAS.pNext = nullptr; + DescrAS.accelerationStructureCount = 1; + DescrAS.pAccelerationStructures = pTLASVk->GetVkTLASPtr(); return DescrAS; } diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index 8a48c27c..45ed73de 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -39,6 +39,7 @@ #include "ShaderResourceVariableBase.hpp" #include "StringTools.hpp" #include "PipelineStateVkImpl.hpp" +#include "TopLevelASVkImpl.hpp" namespace Diligent { @@ -97,7 +98,7 @@ static SHADER_RESOURCE_VARIABLE_TYPE FindShaderVariableType(SHADER_TYPE ShaderResourceLayoutVk::ShaderStageInfo::ShaderStageInfo(SHADER_TYPE Stage, const ShaderVkImpl* pShader) : Type{Stage}, Shaders{{pShader}}, - SPIRVs{{pShader->GetSPIRV()}} + SPIRVs{{{pShader->GetSPIRV()}}} { } @@ -1094,22 +1095,22 @@ void ShaderResourceLayoutVk::VkResource::CacheAccelerationStructure(IDeviceObjec VkDescriptorSet vkDescrSet, Uint32 ArrayInd) const { - // VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration Structure resource is expected"); - // RefCntAutoPtr pTLASVk{pTLAS, IID_TopLevelASVk}; - //#ifdef DILIGENT_DEVELOPMENT - // // AZ TODO - //#endif - // if (UpdateCachedResource(DstRes, std::move(pTLASVk), [](const TopLevelASVkImpl*, const TopLevelASVkImpl*) {})) - // { - // // Do not update descriptor for a dynamic TLAS. All dynamic resource descriptors - // // are updated at once by CommitDynamicResources() when SRB is committed. - // if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - // { - // VkWriteDescriptorSetAccelerationStructureKHR DescrASInfo = DstRes.GetAccelerationStructureWriteInfo(); - // UpdateDescriptorHandle(vkDescrSet, ArrayInd, nullptr, nullptr, nullptr, &DescrASInfo); - // } - // // - // } + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration Structure resource is expected"); + RefCntAutoPtr pTLASVk{pTLAS, IID_TopLevelASVk}; +#ifdef DILIGENT_DEVELOPMENT + // AZ TODO +#endif + if (UpdateCachedResource(DstRes, std::move(pTLASVk), [](const TopLevelASVkImpl*, const TopLevelASVkImpl*) {})) + { + // Do not update descriptor for a dynamic TLAS. All dynamic resource descriptors + // are updated at once by CommitDynamicResources() when SRB is committed. + if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) + { + VkWriteDescriptorSetAccelerationStructureKHR DescrASInfo = DstRes.GetAccelerationStructureWriteInfo(); + UpdateDescriptorHandle(vkDescrSet, ArrayInd, nullptr, nullptr, nullptr, &DescrASInfo); + } + // + } } void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache) const diff --git a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp index ab53d639..27be99fc 100644 --- a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp @@ -423,12 +423,24 @@ void SwapChainVkImpl::CreateVulkanSwapChain() swapchain_ci.imageColorSpace = ColorSpace; DEV_CHECK_ERR(m_SwapChainDesc.Usage != 0, "No swap chain usage flags defined"); - if (m_SwapChainDesc.Usage & SWAP_CHAIN_USAGE_RENDER_TARGET) - swapchain_ci.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - if (m_SwapChainDesc.Usage & SWAP_CHAIN_USAGE_SHADER_INPUT) - swapchain_ci.imageUsage |= VK_IMAGE_USAGE_SAMPLED_BIT; - if (m_SwapChainDesc.Usage & SWAP_CHAIN_USAGE_COPY_SOURCE) - swapchain_ci.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + static_assert(SWAP_CHAIN_USAGE_LAST == SWAP_CHAIN_USAGE_UNORDERED_ACCESS, "Please update this function to handle the new swapchain usage"); + + for (Uint32 UsageBit = 1; UsageBit <= m_SwapChainDesc.Usage; UsageBit <<= 1) + { + if ((m_SwapChainDesc.Usage & UsageBit) == 0) + continue; + + switch (static_cast(UsageBit)) + { + // clang-format off + case SWAP_CHAIN_USAGE_RENDER_TARGET: swapchain_ci.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; break; + case SWAP_CHAIN_USAGE_SHADER_INPUT: swapchain_ci.imageUsage |= VK_IMAGE_USAGE_SAMPLED_BIT; break; + case SWAP_CHAIN_USAGE_COPY_SOURCE: swapchain_ci.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; break; + case SWAP_CHAIN_USAGE_UNORDERED_ACCESS: swapchain_ci.imageUsage |= VK_IMAGE_USAGE_STORAGE_BIT; break; + default: UNEXPECTED("unknown swapchain usage flag"); + // clang-format on + } + } // vkCmdClearColorImage() command requires the image to use VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL layout // that requires VK_IMAGE_USAGE_TRANSFER_DST_BIT to be set @@ -639,9 +651,10 @@ VkResult SwapChainVkImpl::AcquireNextImage(DeviceContextVkImpl* pDeviceCtxVk) m_ImageAcquiredFenceSubmitted[m_SemaphoreIndex] = (res == VK_SUCCESS); if (res == VK_SUCCESS) { - // Next command in the device context must wait for the next image to be acquired - // Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore (6.4.2) - pDeviceCtxVk->AddWaitSemaphore(m_ImageAcquiredSemaphores[m_SemaphoreIndex], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + // Next command in the device context must wait for the next image to be acquired. + // Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore (6.4.2). + // Swapchain may be used as UAV in compute or ray tracing shader, so we must wait on all stages. + pDeviceCtxVk->AddWaitSemaphore(m_ImageAcquiredSemaphores[m_SemaphoreIndex], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); if (!m_SwapChainImagesInitialized[m_BackBufferIndex]) { // Vulkan validation layers do not like uninitialized memory. diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index 488e4bf6..dca627d7 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -223,13 +223,13 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters, // For either clear or copy command, dst layout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL VkImageSubresourceRange SubresRange; - SubresRange.aspectMask = aspectMask; - SubresRange.baseArrayLayer = 0; - SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; - SubresRange.baseMipLevel = 0; - SubresRange.levelCount = VK_REMAINING_MIP_LEVELS; - auto EnabledGraphicsShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages(); - VulkanUtilities::VulkanCommandBuffer::TransitionImageLayout(vkCmdBuff, m_VulkanImage, ImageCI.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange, EnabledGraphicsShaderStages); + SubresRange.aspectMask = aspectMask; + SubresRange.baseArrayLayer = 0; + SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + SubresRange.baseMipLevel = 0; + SubresRange.levelCount = VK_REMAINING_MIP_LEVELS; + auto EnabledShaderStages = LogicalDevice.GetEnabledShaderStages(); + VulkanUtilities::VulkanCommandBuffer::TransitionImageLayout(vkCmdBuff, m_VulkanImage, ImageCI.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange, EnabledShaderStages); SetState(RESOURCE_STATE_COPY_DEST); const auto CurrentLayout = GetLayout(); VERIFY_EXPR(CurrentLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); @@ -350,7 +350,7 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters, err = LogicalDevice.BindBufferMemory(StagingBuffer, StagingBufferMemory, AlignedStagingMemOffset); CHECK_VK_ERROR_AND_THROW(err, "Failed to bind staging bufer memory"); - VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT, EnabledGraphicsShaderStages); + VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT, EnabledShaderStages); // Copy commands MUST be recorded outside of a render pass instance. This is OK here // as copy will be the only command in the cmd buffer diff --git a/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp index 76248d41..ae10b74b 100644 --- a/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp @@ -76,14 +76,14 @@ TopLevelASVkImpl::TopLevelASVkImpl(IReferenceCounters* pRefCounters, LOG_ERROR_AND_THROW("Failed to find suitable memory type for TLAS '", m_Desc.Name, '\''); VERIFY(IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!"); - m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex); + m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex); + m_MemoryAlignedOffset = Align(VkDeviceSize{m_MemoryAllocation.UnalignedOffset}, MemReqs.alignment); + VERIFY(m_MemoryAllocation.Size >= MemReqs.size + (m_MemoryAlignedOffset - m_MemoryAllocation.UnalignedOffset), "Size of memory allocation is too small"); auto Memory = m_MemoryAllocation.Page->GetVkMemory(); - auto err = LogicalDevice.BindASMemory(m_VulkanTLAS, Memory, 0); + auto err = LogicalDevice.BindASMemory(m_VulkanTLAS, Memory, m_MemoryAlignedOffset); CHECK_VK_ERROR_AND_THROW(err, "Failed to bind AS memory"); - m_DeviceAddress = LogicalDevice.GetAccelerationStructureDeviceAddress(m_VulkanTLAS); - MemInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR; MemReqs = LogicalDevice.GetASMemoryRequirements(MemInfo); m_ScratchSize.Build = static_cast(MemReqs.size); diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp index 6358174c..40882b09 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp @@ -1152,6 +1152,55 @@ VkBorderColor BorderColorToVkBorderColor(const Float32 BorderColor[]) } +static VkPipelineStageFlags ResourceStateFlagToVkPipelineStage(RESOURCE_STATE StateFlag, VkPipelineStageFlags ShaderStages) +{ + static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag"); + VERIFY((StateFlag & (StateFlag - 1)) == 0, "Only single bit must be set"); + switch (StateFlag) + { + // clang-format off + case RESOURCE_STATE_UNDEFINED: return 0; + case RESOURCE_STATE_VERTEX_BUFFER: return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + case RESOURCE_STATE_CONSTANT_BUFFER: return ShaderStages; + case RESOURCE_STATE_INDEX_BUFFER: return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + case RESOURCE_STATE_RENDER_TARGET: return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + case RESOURCE_STATE_UNORDERED_ACCESS: return ShaderStages; + case RESOURCE_STATE_DEPTH_WRITE: return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + case RESOURCE_STATE_DEPTH_READ: return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + case RESOURCE_STATE_SHADER_RESOURCE: return ShaderStages; + case RESOURCE_STATE_STREAM_OUT: return 0; + case RESOURCE_STATE_INDIRECT_ARGUMENT: return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; + case RESOURCE_STATE_COPY_DEST: return VK_PIPELINE_STAGE_TRANSFER_BIT; + case RESOURCE_STATE_COPY_SOURCE: return VK_PIPELINE_STAGE_TRANSFER_BIT; + case RESOURCE_STATE_RESOLVE_DEST: return VK_PIPELINE_STAGE_TRANSFER_BIT; + case RESOURCE_STATE_RESOLVE_SOURCE: return VK_PIPELINE_STAGE_TRANSFER_BIT; + case RESOURCE_STATE_INPUT_ATTACHMENT: return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + case RESOURCE_STATE_PRESENT: return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + case RESOURCE_STATE_BUILD_AS_READ: return VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; + case RESOURCE_STATE_BUILD_AS_WRITE: return VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; + case RESOURCE_STATE_RAY_TRACING: return VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; + // clang-format on + + default: + UNEXPECTED("Unexpected resource state flag"); + return 0; + } +} + +VkPipelineStageFlags ResourceStateFlagsToVkPipelineStageFlags(RESOURCE_STATE StateFlags, VkPipelineStageFlags ShaderStages) +{ + VERIFY(Uint32{StateFlags} < (RESOURCE_STATE_MAX_BIT << 1), "Resource state flags are out of range"); + + VkPipelineStageFlags Stages = 0; + for (Uint32 Bit = 1; Bit <= StateFlags; Bit <<= 1) + { + if (StateFlags & Bit) + Stages |= ResourceStateFlagToVkPipelineStage(static_cast(Bit), ShaderStages); + } + return Stages; +} + + static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag) { // Currently not used: @@ -1189,7 +1238,8 @@ static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag) case RESOURCE_STATE_RESOLVE_SOURCE: return VK_ACCESS_TRANSFER_READ_BIT; case RESOURCE_STATE_INPUT_ATTACHMENT: return VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; case RESOURCE_STATE_PRESENT: return 0; - case RESOURCE_STATE_BUILD_AS: return VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; + case RESOURCE_STATE_BUILD_AS_READ: return VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; + case RESOURCE_STATE_BUILD_AS_WRITE: return VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; case RESOURCE_STATE_RAY_TRACING: return VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; // clang-format on @@ -1218,7 +1268,7 @@ public: } private: - static constexpr const Uint32 MaxFlagBitPos = 18; + static constexpr const Uint32 MaxFlagBitPos = 19; std::array FlagBitPosToVkAccessFlagsMap; }; @@ -1239,7 +1289,7 @@ VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags) return AccessFlags; } -RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlagBits AccessFlagBit) +static RESOURCE_STATE VkAccessFlagToResourceStates(VkAccessFlagBits AccessFlagBit) { VERIFY((AccessFlagBit & (AccessFlagBit - 1)) == 0, "Single access flag bit is expected"); @@ -1271,8 +1321,6 @@ RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlagBits AccessFlagBit) case VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV: return RESOURCE_STATE_UNKNOWN; case VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT: return RESOURCE_STATE_UNKNOWN; case VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV: return RESOURCE_STATE_UNKNOWN; - case VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR: return RESOURCE_STATE_RAY_TRACING; - case VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR: return RESOURCE_STATE_BUILD_AS; // clang-format on default: UNEXPECTED("Unknown access flag"); @@ -1288,7 +1336,7 @@ public: { for (Uint32 bit = 0; bit < MaxFlagBitPos; ++bit) { - FlagBitPosToResourceState[bit] = VkAccessFlagsToResourceStates(static_cast(1 << bit)); + FlagBitPosToResourceState[bit] = VkAccessFlagToResourceStates(static_cast(1 << bit)); } } @@ -1354,7 +1402,8 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsi case RESOURCE_STATE_RESOLVE_SOURCE: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; case RESOURCE_STATE_INPUT_ATTACHMENT: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; case RESOURCE_STATE_PRESENT: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - case RESOURCE_STATE_BUILD_AS: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED; + case RESOURCE_STATE_BUILD_AS_READ: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED; + case RESOURCE_STATE_BUILD_AS_WRITE: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED; case RESOURCE_STATE_RAY_TRACING: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED; // clang-format on @@ -1376,7 +1425,7 @@ RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout) case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: return RESOURCE_STATE_DEPTH_WRITE; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: return RESOURCE_STATE_DEPTH_READ; case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return RESOURCE_STATE_SHADER_RESOURCE; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return RESOURCE_STATE_COPY_SOURCE; // AZ TODO: check for resolve state + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return RESOURCE_STATE_COPY_SOURCE; case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return RESOURCE_STATE_COPY_DEST; case VK_IMAGE_LAYOUT_PREINITIALIZED: UNEXPECTED("This layout is not supported"); return RESOURCE_STATE_UNDEFINED; case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: UNEXPECTED("This layout is not supported"); return RESOURCE_STATE_UNDEFINED; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp index 5a1894c0..ae460cde 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp @@ -79,7 +79,7 @@ VulkanUploadHeap::UploadPageInfo VulkanUploadHeap::CreateNewPage(VkDeviceSize Si "at least one bit set corresponding to a VkMemoryType with a propertyFlags that has both the " "VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT bit AND the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit set. (11.6)"); - auto MemAllocation = GlobalMemoryMgr.Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, true); + auto MemAllocation = GlobalMemoryMgr.Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, true, VkMemoryAllocateFlags{0}); auto AlignedOffset = (MemAllocation.UnalignedOffset + (MemReqs.alignment - 1)) & ~(MemReqs.alignment - 1); auto err = LogicalDevice.BindBufferMemory(NewBuffer, MemAllocation.Page->GetVkMemory(), AlignedOffset); diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp index 11444c33..4d47ca3e 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp @@ -32,7 +32,7 @@ namespace VulkanUtilities { static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags AccessFlags, - const VkPipelineStageFlags EnabledGraphicsShaderStages) + const VkPipelineStageFlags EnabledShaderStages) { // 6.1.3 VkPipelineStageFlags Stages = 0; @@ -65,7 +65,7 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags // Read access to a uniform buffer case VK_ACCESS_UNIFORM_READ_BIT: - Stages |= EnabledGraphicsShaderStages | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + Stages |= EnabledShaderStages; break; // Read access to an input attachment within a render pass during fragment shading @@ -75,12 +75,12 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags // Read access to a storage buffer, uniform texel buffer, storage texel buffer, sampled image, or storage image case VK_ACCESS_SHADER_READ_BIT: - Stages |= EnabledGraphicsShaderStages | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + Stages |= EnabledShaderStages; break; // Write access to a storage buffer, storage texel buffer, or storage image case VK_ACCESS_SHADER_WRITE_BIT: - Stages |= EnabledGraphicsShaderStages | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + Stages |= EnabledShaderStages; break; // Read access to a color attachment, such as via blending, logic operations, or via certain subpass load operations @@ -134,6 +134,16 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags case VK_ACCESS_MEMORY_WRITE_BIT: break; + // AZ TODO: comment + case VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR: + Stages |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; + break; + + // AZ TODO: comment + case VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR: + Stages |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; + break; + default: UNEXPECTED("Unknown memory access flag"); } @@ -223,8 +233,12 @@ static VkPipelineStageFlags AccessMaskFromImageLayout(VkImageLayout Layout, AccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; break; + // When transitioning the image to VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + // there is no need to delay subsequent processing, or perform any visibility operations (as vkQueuePresentKHR + // performs automatic visibility operations). To achieve this, the dstAccessMask member of the VkImageMemoryBarrier + // should be set to 0, and the dstStageMask parameter should be set to VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT. case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - AccessMask = VK_ACCESS_MEMORY_READ_BIT; + AccessMask = 0; break; default: @@ -240,7 +254,7 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer C VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange, - VkPipelineStageFlags EnabledGraphicsShaderStages, + VkPipelineStageFlags EnabledShaderStages, VkPipelineStageFlags SrcStages, VkPipelineStageFlags DestStages) { @@ -268,7 +282,7 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer C } else if (ImgBarrier.srcAccessMask != 0) { - SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask, EnabledGraphicsShaderStages); + SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask, EnabledShaderStages); } else { @@ -282,11 +296,11 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer C { if (NewLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { - DestStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + DestStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; } else if (ImgBarrier.dstAccessMask != 0) { - DestStages = PipelineStageFromAccessFlags(ImgBarrier.dstAccessMask, EnabledGraphicsShaderStages); + DestStages = PipelineStageFromAccessFlags(ImgBarrier.dstAccessMask, EnabledShaderStages); } else { @@ -327,7 +341,7 @@ void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer, VkBuffer Buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, - VkPipelineStageFlags EnabledGraphicsShaderStages, + VkPipelineStageFlags EnabledShaderStages, VkPipelineStageFlags SrcStages, VkPipelineStageFlags DestStages) { @@ -344,7 +358,7 @@ void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer, if (SrcStages == 0) { if (BuffBarrier.srcAccessMask != 0) - SrcStages = PipelineStageFromAccessFlags(BuffBarrier.srcAccessMask, EnabledGraphicsShaderStages); + SrcStages = PipelineStageFromAccessFlags(BuffBarrier.srcAccessMask, EnabledShaderStages); else { // An execution dependency with only VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT in the source stage @@ -356,7 +370,7 @@ void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer, if (DestStages == 0) { VERIFY(BuffBarrier.dstAccessMask != 0, "Dst access mask must not be zero"); - DestStages = PipelineStageFromAccessFlags(BuffBarrier.dstAccessMask, EnabledGraphicsShaderStages); + DestStages = PipelineStageFromAccessFlags(BuffBarrier.dstAccessMask, EnabledShaderStages); } vkCmdPipelineBarrier(CmdBuffer, @@ -371,6 +385,55 @@ void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer, nullptr); } +void VulkanCommandBuffer::ASMemoryBarrier(VkCommandBuffer CmdBuffer, + VkAccessFlags srcAccessMask, + VkAccessFlags dstAccessMask, + VkPipelineStageFlags EnabledShaderStages, + VkPipelineStageFlags SrcStages, + VkPipelineStageFlags DestStages) +{ + VkMemoryBarrier Barrier = {}; + Barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + Barrier.pNext = nullptr; + Barrier.srcAccessMask = srcAccessMask; + Barrier.dstAccessMask = dstAccessMask; + + if (SrcStages == 0) + { + if (Barrier.srcAccessMask != 0) + SrcStages = PipelineStageFromAccessFlags(Barrier.srcAccessMask, EnabledShaderStages); + else + { + // An execution dependency with only VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT in the source stage + // mask will effectively not wait for any prior commands to complete. (6.1.2) + SrcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + } + } + + if (DestStages == 0) + { + VERIFY(Barrier.dstAccessMask != 0, "Dst access mask must not be zero"); + DestStages = PipelineStageFromAccessFlags(Barrier.dstAccessMask, EnabledShaderStages); + } + + // Other stages are not valid for acceleration structures + constexpr VkPipelineStageFlags StagesMask = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + + SrcStages &= StagesMask; + DestStages &= StagesMask; + + vkCmdPipelineBarrier(CmdBuffer, + SrcStages, // must not be 0 + DestStages, // must not be 0 + 0, // a bitmask specifying how execution and memory dependencies are formed + 1, // memoryBarrierCount + &Barrier, // pMemoryBarriers + 0, + nullptr, + 0, + nullptr); +} + void VulkanCommandBuffer::FlushBarriers() { } diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp index 358bdec5..7639c309 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp @@ -64,15 +64,19 @@ VulkanLogicalDevice::VulkanLogicalDevice(const VulkanPhysicalDevice& PhysicalDe // https://github.com/zeux/volk#optimizing-device-calls volkLoadDevice(m_VkDevice); - if (PhysicalDevice.GetExtFeatures().RayTracingNV) + if (m_EnabledExtFeatures.RayTracingNV) EnableRayTracingKHRviaNV(); #endif - m_EnabledGraphicsShaderStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + m_EnabledShaderStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; if (DeviceCI.pEnabledFeatures->geometryShader) - m_EnabledGraphicsShaderStages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; + m_EnabledShaderStages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; if (DeviceCI.pEnabledFeatures->tessellationShader) - m_EnabledGraphicsShaderStages |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; + m_EnabledShaderStages |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; + if (m_EnabledExtFeatures.MeshShader.meshShader != VK_FALSE && m_EnabledExtFeatures.MeshShader.taskShader != VK_FALSE) + m_EnabledShaderStages |= VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV | VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV; + if (m_EnabledExtFeatures.RayTracing.rayTracing != VK_FALSE) + m_EnabledShaderStages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; } VkQueue VulkanLogicalDevice::GetQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp index f9cdcdea..2e2cdd31 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp @@ -40,10 +40,11 @@ VulkanMemoryAllocation::~VulkanMemoryAllocation() } } -VulkanMemoryPage::VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr, - VkDeviceSize PageSize, - uint32_t MemoryTypeIndex, - bool IsHostVisible) noexcept : +VulkanMemoryPage::VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr, + VkDeviceSize PageSize, + uint32_t MemoryTypeIndex, + bool IsHostVisible, + VkMemoryAllocateFlags AllocateFlags) noexcept : // clang-format off m_ParentMemoryMgr{ParentMemoryMgr}, m_AllocationMgr {static_cast(PageSize), ParentMemoryMgr.m_Allocator} @@ -53,13 +54,22 @@ VulkanMemoryPage::VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr, "PageSize (", PageSize, ") exceeds maximum allowed value ", std::numeric_limits::max()); - VkMemoryAllocateInfo MemAlloc = {}; + VkMemoryAllocateInfo MemAlloc = {}; + VkMemoryAllocateFlagsInfo MemFlagInfo = {}; MemAlloc.pNext = nullptr; MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; MemAlloc.allocationSize = PageSize; MemAlloc.memoryTypeIndex = MemoryTypeIndex; + if (AllocateFlags) + { + MemAlloc.pNext = &MemFlagInfo; + MemFlagInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + MemFlagInfo.pNext = nullptr; + MemFlagInfo.flags = AllocateFlags; + } + auto MemoryName = Diligent::FormatString("Device memory page. Size: ", Diligent::FormatMemorySize(PageSize, 2), ", type: ", MemoryTypeIndex); m_VkMemory = ParentMemoryMgr.m_LogicalDevice.AllocateDeviceMemory(MemAlloc, MemoryName.c_str()); @@ -116,7 +126,7 @@ void VulkanMemoryPage::Free(VulkanMemoryAllocation&& Allocation) Allocation = VulkanMemoryAllocation{}; } -VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps) +VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps, VkMemoryAllocateFlags AllocateFlags) { // memoryTypeBits is a bitmask and contains one bit set for every supported memory type for the resource. // Bit i is set if and only if the memory type i in the VkPhysicalDeviceMemoryProperties structure for the @@ -145,10 +155,10 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements& } bool HostVisible = (MemoryProps & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; - return Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, HostVisible); + return Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, HostVisible, AllocateFlags); } -VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible) +VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible, VkMemoryAllocateFlags AllocateFlags) { VulkanMemoryAllocation Allocation; @@ -159,7 +169,7 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDevice // even though on integrated GPUs same pages can be used for both GPU-only and staging // allocations. Staging allocations are short-living and will be released when upload is // complete, while GPU-only allocations are expected to be long-living. - MemoryPageIndex PageIdx{MemoryTypeIndex, HostVisible}; + MemoryPageIndex PageIdx{MemoryTypeIndex, HostVisible, AllocateFlags}; std::lock_guard Lock{m_PagesMtx}; auto range = m_Pages.equal_range(PageIdx); @@ -180,7 +190,7 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDevice m_CurrAllocatedSize[stat_ind] += PageSize; m_PeakAllocatedSize[stat_ind] = std::max(m_PeakAllocatedSize[stat_ind], m_CurrAllocatedSize[stat_ind]); - auto it = m_Pages.emplace(PageIdx, VulkanMemoryPage{*this, PageSize, MemoryTypeIndex, HostVisible}); + auto it = m_Pages.emplace(PageIdx, VulkanMemoryPage{*this, PageSize, MemoryTypeIndex, HostVisible, AllocateFlags}); LOG_INFO_MESSAGE("VulkanMemoryManager '", m_MgrName, "': created new ", (HostVisible ? "host-visible" : "device-local"), " page. (", Diligent::FormatMemorySize(PageSize, 2), ", type idx: ", MemoryTypeIndex, "). Current allocated size: ", Diligent::FormatMemorySize(m_CurrAllocatedSize[stat_ind], 2)); diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanRayTracingKHRviaNV.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanRayTracingKHRviaNV.cpp index f7a6b8f6..5b5434d5 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanRayTracingKHRviaNV.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanRayTracingKHRviaNV.cpp @@ -56,18 +56,18 @@ PFN_vkCreateBuffer Origin_vkCreateBuffer = nullptr; PFN_vkDestroyBuffer Origin_vkDestroyBuffer = nullptr; PFN_vkGetBufferDeviceAddressKHR Origin_vkGetBufferDeviceAddressKHR = nullptr; -VkResult VKAPI_CALL Wrap_vkCreateBuffer(VkDevice device, - const VkBufferCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkBuffer* pBuffer) +VKAPI_ATTR VkResult VKAPI_CALL Wrap_vkCreateBuffer(VkDevice device, + const VkBufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBuffer* pBuffer) { const_cast(pCreateInfo)->usage &= ~VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; return Origin_vkCreateBuffer(device, pCreateInfo, pAllocator, pBuffer); } -void VKAPI_CALL Wrap_vkDestroyBuffer(VkDevice device, - VkBuffer buffer, - const VkAllocationCallbacks* pAllocator) +VKAPI_ATTR void VKAPI_CALL Wrap_vkDestroyBuffer(VkDevice device, + VkBuffer buffer, + const VkAllocationCallbacks* pAllocator) { Origin_vkDestroyBuffer(device, buffer, pAllocator); @@ -81,8 +81,8 @@ void VKAPI_CALL Wrap_vkDestroyBuffer(VkDevice device, } } -VkDeviceAddress VKAPI_CALL Wrap_vkGetBufferDeviceAddressKHR(VkDevice device, - const VkBufferDeviceAddressInfo* pInfo) +VKAPI_ATTR VkDeviceAddress VKAPI_CALL Wrap_vkGetBufferDeviceAddressKHR(VkDevice device, + const VkBufferDeviceAddressInfo* pInfo) { VERIFY_EXPR(pInfo->sType == VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR); VERIFY_EXPR(pInfo->pNext == nullptr); @@ -134,10 +134,10 @@ BufferAndOffset DeviceAddressToBuffer(const VkDeviceOrHostAddressKHR& Addr) } -VkResult VKAPI_CALL Redirect_vkCreateAccelerationStructureKHR(VkDevice device, - const VkAccelerationStructureCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkAccelerationStructureKHR* pAccelerationStructure) +VKAPI_ATTR VkResult VKAPI_CALL Redirect_vkCreateAccelerationStructureKHR(VkDevice device, + const VkAccelerationStructureCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureKHR* pAccelerationStructure) { VERIFY_EXPR(pCreateInfo->sType == VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR); VERIFY_EXPR(pCreateInfo->pNext == nullptr); @@ -154,7 +154,9 @@ VkResult VKAPI_CALL Redirect_vkCreateAccelerationStructureKHR(VkDevice if (CreateInfo.info.type == VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) { - CreateInfo.info.instanceCount = pCreateInfo->maxGeometryCount; + VERIFY_EXPR(pCreateInfo->maxGeometryCount == 1); + + CreateInfo.info.instanceCount = pCreateInfo->pGeometryInfos->maxPrimitiveCount; } else if (CreateInfo.info.type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) { @@ -183,7 +185,6 @@ VkResult VKAPI_CALL Redirect_vkCreateAccelerationStructureKHR(VkDevice { dst.geometry.triangles.vertexData = VK_NULL_HANDLE; dst.geometry.triangles.vertexOffset = 0; - dst.geometry.triangles.vertexCount = src.maxVertexCount; dst.geometry.triangles.vertexStride = 0; dst.geometry.triangles.vertexFormat = src.vertexFormat; dst.geometry.triangles.indexData = VK_NULL_HANDLE; @@ -200,7 +201,8 @@ VkResult VKAPI_CALL Redirect_vkCreateAccelerationStructureKHR(VkDevice } else { - dst.geometry.triangles.indexCount = src.maxPrimitiveCount * 3; + dst.geometry.triangles.indexCount = src.maxPrimitiveCount * 3; + dst.geometry.triangles.vertexCount = std::max(src.maxPrimitiveCount * 6, src.maxVertexCount); } } else if (dst.geometryType == VK_GEOMETRY_TYPE_AABBS_KHR) @@ -224,11 +226,12 @@ VkResult VKAPI_CALL Redirect_vkCreateAccelerationStructureKHR(VkDevice return vkCreateAccelerationStructureNV(device, &CreateInfo, pAllocator, reinterpret_cast(pAccelerationStructure)); } -void VKAPI_CALL Redirect_vkGetAccelerationStructureMemoryRequirementsKHR(VkDevice device, - const VkAccelerationStructureMemoryRequirementsInfoKHR* pInfo, - VkMemoryRequirements2* pMemoryRequirements) +VKAPI_ATTR void VKAPI_CALL Redirect_vkGetAccelerationStructureMemoryRequirementsKHR(VkDevice device, + const VkAccelerationStructureMemoryRequirementsInfoKHR* pInfo, + VkMemoryRequirements2* pMemoryRequirements) { VERIFY_EXPR(pInfo->sType == VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR); + VERIFY_EXPR(pMemoryRequirements->sType == VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2); VERIFY_EXPR(pInfo->pNext == nullptr); VERIFY_EXPR(pInfo->buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR); @@ -241,16 +244,16 @@ void VKAPI_CALL Redirect_vkGetAccelerationStructureMemoryRequirementsKHR(VkDevic return vkGetAccelerationStructureMemoryRequirementsNV(device, &Info, pMemoryRequirements); } -VkResult VKAPI_CALL Redirect_vkBindAccelerationStructureMemoryKHR(VkDevice device, - uint32_t bindInfoCount, - const VkBindAccelerationStructureMemoryInfoKHR* pBindInfos) +VKAPI_ATTR VkResult VKAPI_CALL Redirect_vkBindAccelerationStructureMemoryKHR(VkDevice device, + uint32_t bindInfoCount, + const VkBindAccelerationStructureMemoryInfoKHR* pBindInfos) { VERIFY_EXPR(pBindInfos->sType == VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV); return vkBindAccelerationStructureMemoryNV(device, bindInfoCount, pBindInfos); } -VkDeviceAddress VKAPI_CALL Redirect_vkGetAccelerationStructureDeviceAddressKHR(VkDevice device, - const VkAccelerationStructureDeviceAddressInfoKHR* pInfo) +VKAPI_ATTR VkDeviceAddress VKAPI_CALL Redirect_vkGetAccelerationStructureDeviceAddressKHR(VkDevice device, + const VkAccelerationStructureDeviceAddressInfoKHR* pInfo) { VERIFY_EXPR(pInfo->sType == VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR); VERIFY_EXPR(pInfo->pNext == nullptr); @@ -260,10 +263,10 @@ VkDeviceAddress VKAPI_CALL Redirect_vkGetAccelerationStructureDeviceAddressKHR(V return result; } -void VKAPI_CALL Redirect_vkCmdBuildAccelerationStructureKHR(VkCommandBuffer commandBuffer, - uint32_t infoCount, - const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, - const VkAccelerationStructureBuildOffsetInfoKHR* const* ppOffsetInfos) +VKAPI_ATTR void VKAPI_CALL Redirect_vkCmdBuildAccelerationStructureKHR(VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkAccelerationStructureBuildOffsetInfoKHR* const* ppOffsetInfos) { std::vector Geometries; @@ -321,6 +324,12 @@ void VKAPI_CALL Redirect_vkCmdBuildAccelerationStructureKHR(VkCommandBuffer dst.flags = src.flags; dst.geometryType = src.geometryType; + dst.geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV; + dst.geometry.triangles.pNext = nullptr; + + dst.geometry.aabbs.sType = VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV; + dst.geometry.aabbs.pNext = nullptr; + if (dst.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR) { VERIFY_EXPR(src.geometry.triangles.sType == VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR); @@ -331,8 +340,6 @@ void VKAPI_CALL Redirect_vkCmdBuildAccelerationStructureKHR(VkCommandBuffer BufferAndOffset IB = DeviceAddressToBuffer(src.geometry.triangles.indexData); BufferAndOffset TB = DeviceAddressToBuffer(src.geometry.triangles.transformData); - dst.geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV; - dst.geometry.triangles.pNext = nullptr; dst.geometry.triangles.vertexData = VB.Buffer; dst.geometry.triangles.vertexOffset = VB.Offset; dst.geometry.triangles.vertexCount = 0; @@ -353,7 +360,8 @@ void VKAPI_CALL Redirect_vkCmdBuildAccelerationStructureKHR(VkCommandBuffer else { dst.geometry.triangles.indexOffset += off.primitiveOffset; - dst.geometry.triangles.indexCount = off.primitiveCount * 3; + dst.geometry.triangles.indexCount = off.primitiveCount * 3; + dst.geometry.triangles.vertexCount = off.primitiveCount * 6; } } else @@ -364,8 +372,6 @@ void VKAPI_CALL Redirect_vkCmdBuildAccelerationStructureKHR(VkCommandBuffer BufferAndOffset Data = DeviceAddressToBuffer(src.geometry.aabbs.data); - dst.geometry.aabbs.sType = VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV; - dst.geometry.aabbs.pNext = nullptr; dst.geometry.aabbs.aabbData = Data.Buffer; dst.geometry.aabbs.numAABBs = off.primitiveCount; dst.geometry.aabbs.stride = static_cast(src.geometry.aabbs.stride); @@ -389,8 +395,8 @@ void VKAPI_CALL Redirect_vkCmdBuildAccelerationStructureKHR(VkCommandBuffer } } -void VKAPI_CALL Redirect_vkCmdCopyAccelerationStructureKHR(VkCommandBuffer commandBuffer, - const VkCopyAccelerationStructureInfoKHR* pInfo) +VKAPI_ATTR void VKAPI_CALL Redirect_vkCmdCopyAccelerationStructureKHR(VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureInfoKHR* pInfo) { VERIFY_EXPR(pInfo->sType == VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR); VERIFY_EXPR(pInfo->pNext == nullptr); @@ -398,14 +404,14 @@ void VKAPI_CALL Redirect_vkCmdCopyAccelerationStructureKHR(VkCommandBuffer vkCmdCopyAccelerationStructureNV(commandBuffer, pInfo->dst, pInfo->src, pInfo->mode); } -void VKAPI_CALL Redirect_vkCmdTraceRaysKHR(VkCommandBuffer commandBuffer, - const VkStridedBufferRegionKHR* pRaygenShaderBindingTable, - const VkStridedBufferRegionKHR* pMissShaderBindingTable, - const VkStridedBufferRegionKHR* pHitShaderBindingTable, - const VkStridedBufferRegionKHR* pCallableShaderBindingTable, - uint32_t width, - uint32_t height, - uint32_t depth) +VKAPI_ATTR void VKAPI_CALL Redirect_vkCmdTraceRaysKHR(VkCommandBuffer commandBuffer, + const VkStridedBufferRegionKHR* pRaygenShaderBindingTable, + const VkStridedBufferRegionKHR* pMissShaderBindingTable, + const VkStridedBufferRegionKHR* pHitShaderBindingTable, + const VkStridedBufferRegionKHR* pCallableShaderBindingTable, + uint32_t width, + uint32_t height, + uint32_t depth) { vkCmdTraceRaysNV(commandBuffer, pRaygenShaderBindingTable->buffer, pRaygenShaderBindingTable->offset, @@ -415,22 +421,28 @@ void VKAPI_CALL Redirect_vkCmdTraceRaysKHR(VkCommandBuffer comma width, height, depth); } -VkResult VKAPI_CALL Redirect_vkGetRayTracingShaderGroupHandlesKHR(VkDevice device, - VkPipeline pipeline, - uint32_t firstGroup, - uint32_t groupCount, - size_t dataSize, - void* pData) +VKAPI_ATTR VkResult VKAPI_CALL Redirect_vkGetRayTracingShaderGroupHandlesKHR(VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData) { return vkGetRayTracingShaderGroupHandlesNV(device, pipeline, firstGroup, groupCount, dataSize, pData); } -VkResult VKAPI_CALL Redirect_vkCreateRayTracingPipelinesKHR(VkDevice device, - VkPipelineCache pipelineCache, - uint32_t createInfoCount, - const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines) +VKAPI_ATTR void VKAPI_CALL Redirect_vkDestroyAccelerationStructureKHR(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks* pAllocator) +{ + return vkDestroyAccelerationStructureNV(device, accelerationStructure, pAllocator); +} + + +VKAPI_ATTR VkResult VKAPI_CALL Redirect_vkCreateRayTracingPipelinesKHR(VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines) { std::vector Infos; std::vector Groups; @@ -506,6 +518,7 @@ void EnableRayTracingKHRviaNV() vkGetRayTracingShaderGroupHandlesKHR = &Redirect_vkGetRayTracingShaderGroupHandlesKHR; vkCreateRayTracingPipelinesKHR = &Redirect_vkCreateRayTracingPipelinesKHR; vkCmdTraceRaysKHR = &Redirect_vkCmdTraceRaysKHR; + vkDestroyAccelerationStructureKHR = &Redirect_vkDestroyAccelerationStructureKHR; Origin_vkGetBufferDeviceAddressKHR = vkGetBufferDeviceAddressKHR; Origin_vkCreateBuffer = vkCreateBuffer; -- cgit v1.2.3