diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-11-07 02:59:30 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-11-07 02:59:30 +0000 |
| commit | 9e1f494d613fad30f63adbd5735ff42bc87fc1f4 (patch) | |
| tree | 571c72b4ff65e31019b4dbc5f71dff0129b0fc0b /Graphics/GraphicsEngine | |
| parent | Updated ResourceMappingImpl (diff) | |
| download | DiligentCore-9e1f494d613fad30f63adbd5735ff42bc87fc1f4.tar.gz DiligentCore-9e1f494d613fad30f63adbd5735ff42bc87fc1f4.zip | |
Device context: refactored command parameters validation
Diffstat (limited to 'Graphics/GraphicsEngine')
| -rw-r--r-- | Graphics/GraphicsEngine/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/include/BottomLevelASBase.hpp | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/include/DeviceContextBase.hpp | 1457 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/include/FramebufferBase.hpp | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/interface/BottomLevelAS.h | 1 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/src/DeviceContextBase.cpp | 704 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/src/FramebufferBase.cpp | 2 |
7 files changed, 1090 insertions, 1079 deletions
diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt index ebb14167..604f3442 100644 --- a/Graphics/GraphicsEngine/CMakeLists.txt +++ b/Graphics/GraphicsEngine/CMakeLists.txt @@ -70,6 +70,7 @@ set(SOURCE src/BottomLevelASBase.cpp src/BufferBase.cpp src/DefaultShaderSourceStreamFactory.cpp + src/DeviceContextBase.cpp src/EngineMemory.cpp src/FramebufferBase.cpp src/PipelineStateBase.cpp diff --git a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp index 2f4a26d0..3ec0efd2 100644 --- a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp +++ b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp @@ -93,8 +93,6 @@ public: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BottomLevelAS, TDeviceObjectBase) - static constexpr Uint32 InvalidGeometryIndex = ~0u; - virtual Uint32 DILIGENT_CALL_TYPE GetGeometryIndex(const char* Name) const override final { VERIFY_EXPR(Name != nullptr && Name[0] != '\0'); diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index ee9a2dd4..1df4682d 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -45,6 +45,36 @@ namespace Diligent { +// clang-format off +bool VerifyDrawAttribs (const DrawAttribs& Attribs); +bool VerifyDrawIndexedAttribs (const DrawIndexedAttribs& Attribs); +bool VerifyDrawIndirectAttribs (const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer); +bool VerifyDrawIndexedIndirectAttribs(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer); + +bool VerifyDispatchComputeAttribs (const DispatchComputeAttribs& Attribs); +bool VerifyDispatchComputeIndirectAttribs(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer); +// clang-format on + +bool VerifyDrawMeshAttribs(Uint32 MaxDrawMeshTasksCount, const DrawMeshAttribs& Attribs); +bool VerifyDrawMeshIndirectAttribs(const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer); + +bool VerifyResolveTextureSubresourceAttribs(const ResolveTextureSubresourceAttribs& ResolveAttribs, + const TextureDesc& SrcTexDesc, + const TextureDesc& DstTexDesc); + +bool VerifyBeginRenderPassAttribs(const BeginRenderPassAttribs& Attribs); +bool VerifyStateTransitionDesc(const IRenderDevice* pDevice, const StateTransitionDesc& Barrier); + +bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs); +bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs); +bool VerifyCopyBLASAttribs(const CopyBLASAttribs& Attribs); +bool VerifyCopyTLASAttribs(const CopyTLASAttribs& Attribs); +bool VerifyWriteBLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteBLASCompactedSizeAttribs& Attribs); +bool VerifyWriteTLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteTLASCompactedSizeAttribs& Attribs); +bool VerifyTraceRaysAttribs(const TraceRaysAttribs& Attribs); + + + /// Describes input vertex stream template <typename BufferImplType> struct VertexStreamInfo @@ -53,7 +83,9 @@ struct VertexStreamInfo /// Strong reference to the buffer object RefCntAutoPtr<BufferImplType> pBuffer; - Uint32 Offset = 0; ///< Offset in bytes + + /// Offset in bytes + Uint32 Offset = 0; }; /// Base implementation of the device context. @@ -62,7 +94,7 @@ struct VertexStreamInfo /// \tparam ImplementationTraits - implementation traits that define specific implementation details /// (texture implemenation type, buffer implementation type, etc.) /// \remarks Device context keeps strong references to all objects currently bound to -/// the pipeline: buffers, states, samplers, shaders, etc. +/// the pipeline: buffers, tetxures, states, SRBs, etc. /// The context also keeps strong references to the device and /// the swap chain. template <typename BaseInterface, typename ImplementationTraits> @@ -81,9 +113,9 @@ public: using BottomLevelASType = typename ImplementationTraits::BottomLevelASType; using TopLevelASType = typename ImplementationTraits::TopLevelASType; - /// \param pRefCounters - reference counters object that controls the lifetime of this device context. + /// \param pRefCounters - reference counters object that controls the lifetime of this device context. /// \param pRenderDevice - render device. - /// \param bIsDeferred - flag indicating if this instance is a deferred context + /// \param bIsDeferred - flag indicating if this instance is a deferred context DeviceContextBase(IReferenceCounters* pRefCounters, DeviceImplType* pRenderDevice, bool bIsDeferred) : // clang-format off TObjectBase {pRefCounters }, @@ -116,7 +148,9 @@ public: int); /// Base implementation of IDeviceContext::SetIndexBuffer(); caches the strong reference to the index buffer - inline virtual void DILIGENT_CALL_TYPE SetIndexBuffer(IBuffer* pIndexBuffer, Uint32 ByteOffset, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) override = 0; + inline virtual void DILIGENT_CALL_TYPE SetIndexBuffer(IBuffer* pIndexBuffer, + Uint32 ByteOffset, + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) override = 0; /// Caches the viewports inline void SetViewports(Uint32 NumViewports, const Viewport* pViewports, Uint32& RTWidth, Uint32& RTHeight); @@ -243,22 +277,22 @@ protected: #ifdef DILIGENT_DEVELOPMENT // clang-format off - bool DvpVerifyDrawArguments (const DrawAttribs& Attribs)const; - bool DvpVerifyDrawIndexedArguments (const DrawIndexedAttribs& Attribs)const; - bool DvpVerifyDrawMeshArguments (const DrawMeshAttribs& Attribs)const; - bool DvpVerifyDrawIndirectArguments (const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const; - bool DvpVerifyDrawIndexedIndirectArguments(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const; - bool DvpVerifyDrawMeshIndirectArguments (const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const; - - bool DvpVerifyDispatchArguments (const DispatchComputeAttribs& Attribs)const; - bool DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const; - - 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 DvpVerifyBLASState (const BottomLevelASType& BLAS, RESOURCE_STATE RequiredState, const char* OperationName)const; - bool DvpVerifyTLASState (const TopLevelASType& TLAS, RESOURCE_STATE RequiredState, const char* OperationName)const; + bool DvpVerifyDrawArguments (const DrawAttribs& Attribs) const; + bool DvpVerifyDrawIndexedArguments (const DrawIndexedAttribs& Attribs) const; + bool DvpVerifyDrawMeshArguments (const DrawMeshAttribs& Attribs) const; + bool DvpVerifyDrawIndirectArguments (const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const; + bool DvpVerifyDrawIndexedIndirectArguments(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const; + bool DvpVerifyDrawMeshIndirectArguments (const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const; + + bool DvpVerifyDispatchArguments (const DispatchComputeAttribs& Attribs) const; + bool DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const; + + bool DvpVerifyRenderTargets() const; + bool 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 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;} @@ -270,8 +304,8 @@ protected: bool DvpVerifyDispatchArguments (const DispatchComputeAttribs& Attribs)const {return true;} bool DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const {return true;} - void DvpVerifyRenderTargets()const {} - void DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier)const {} + bool DvpVerifyRenderTargets()const {return true;} + bool DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier)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;} @@ -368,13 +402,13 @@ protected: template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - SetVertexBuffers(Uint32 StartSlot, - Uint32 NumBuffersSet, - IBuffer** ppBuffers, - Uint32* pOffsets, - RESOURCE_STATE_TRANSITION_MODE StateTransitionMode, - SET_VERTEX_BUFFERS_FLAGS Flags) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetVertexBuffers( + Uint32 StartSlot, + Uint32 NumBuffersSet, + IBuffer** ppBuffers, + Uint32* pOffsets, + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode, + SET_VERTEX_BUFFERS_FLAGS Flags) { #ifdef DILIGENT_DEVELOPMENT if (StartSlot >= MAX_BUFFER_SLOTS) @@ -429,15 +463,18 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - SetPipelineState(PipelineStateImplType* pPipelineState, int /*Dummy*/) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetPipelineState( + PipelineStateImplType* pPipelineState, + int /*Dummy*/) { m_pPipelineState = pPipelineState; } template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - CommitShaderResources(IShaderResourceBinding* pShaderResourceBinding, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode, int) +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::CommitShaderResources( + IShaderResourceBinding* pShaderResourceBinding, + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode, + int) { #ifdef DILIGENT_DEVELOPMENT VERIFY(!(m_pActiveRenderPass != nullptr && StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION), @@ -459,6 +496,7 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: } } #endif + return true; } @@ -472,8 +510,10 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::InvalidateSt } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - SetIndexBuffer(IBuffer* pIndexBuffer, Uint32 ByteOffset, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetIndexBuffer( + IBuffer* pIndexBuffer, + Uint32 ByteOffset, + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) { m_pIndexBuffer = ValidatedCast<BufferImplType>(pIndexBuffer); m_IndexDataStartOffset = ByteOffset; @@ -538,8 +578,11 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::SetStencilRe } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - SetViewports(Uint32 NumViewports, const Viewport* pViewports, Uint32& RTWidth, Uint32& RTHeight) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetViewports( + Uint32 NumViewports, + const Viewport* pViewports, + Uint32& RTWidth, + Uint32& RTHeight) { if (RTWidth == 0 || RTHeight == 0) { @@ -578,8 +621,11 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::GetViewports } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - SetScissorRects(Uint32 NumRects, const Rect* pRects, Uint32& RTWidth, Uint32& RTHeight) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetScissorRects( + Uint32 NumRects, + const Rect* pRects, + Uint32& RTWidth, + Uint32& RTHeight) { if (RTWidth == 0 || RTHeight == 0) { @@ -599,8 +645,10 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: } template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - SetRenderTargets(Uint32 NumRenderTargets, ITextureView* ppRenderTargets[], ITextureView* pDepthStencil) +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::SetRenderTargets( + Uint32 NumRenderTargets, + ITextureView* ppRenderTargets[], + ITextureView* pDepthStencil) { if (NumRenderTargets == 0 && pDepthStencil == nullptr) { @@ -752,8 +800,10 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::SetSubpassRe template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - GetRenderTargets(Uint32& NumRenderTargets, ITextureView** ppRTVs, ITextureView** ppDSV) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::GetRenderTargets( + Uint32& NumRenderTargets, + ITextureView** ppRTVs, + ITextureView** ppDSV) { NumRenderTargets = m_NumBoundRenderTargets; @@ -931,33 +981,8 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::BeginRenderP { VERIFY(m_pActiveRenderPass == nullptr, "Attempting to begin render pass while another render pass ('", m_pActiveRenderPass->GetDesc().Name, "') is active."); VERIFY(m_pBoundFramebuffer == nullptr, "Attempting to begin render pass while another framebuffer ('", m_pBoundFramebuffer->GetDesc().Name, "') is bound."); - VERIFY(Attribs.pRenderPass != nullptr, "Render pass must not be null"); - VERIFY(Attribs.pFramebuffer != nullptr, "Framebuffer must not be null"); -#ifdef DILIGENT_DEBUG - { - const auto& RPDesc = Attribs.pRenderPass->GetDesc(); - - Uint32 NumRequiredClearValues = 0; - for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i) - { - const auto& Attchmnt = RPDesc.pAttachments[i]; - if (Attchmnt.LoadOp == ATTACHMENT_LOAD_OP_CLEAR) - NumRequiredClearValues = i + 1; - const auto& FmtAttribs = GetTextureFormatAttribs(Attchmnt.Format); - if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) - { - if (Attchmnt.StencilLoadOp == ATTACHMENT_LOAD_OP_CLEAR) - NumRequiredClearValues = i + 1; - } - } - VERIFY(Attribs.ClearValueCount >= NumRequiredClearValues, - "Begin render pass operation requiers at least ", NumRequiredClearValues, - " clear values, but only ", Attribs.ClearValueCount, " are given."); - VERIFY(Attribs.ClearValueCount == 0 || Attribs.pClearValues != nullptr, - "pClearValues must not be null when ClearValueCount is not zero"); - } -#endif + VerifyBeginRenderPassAttribs(Attribs); // Reset current render targets (in Vulkan backend, this may end current render pass). ResetRenderTargets(); @@ -998,6 +1023,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::BeginRenderP m_pBoundFramebuffer = pNewFramebuffer; m_SubpassIndex = 0; m_RenderPassAttachmentsTransitionMode = Attribs.StateTransitionMode; + UpdateAttachmentStates(m_SubpassIndex); SetSubpassRenderTargets(); } @@ -1212,8 +1238,12 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::EndQuery(IQu } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - UpdateBuffer(IBuffer* pBuffer, Uint32 Offset, Uint32 Size, const void* pData, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::UpdateBuffer( + IBuffer* pBuffer, + Uint32 Offset, + Uint32 Size, + const void* pData, + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) { VERIFY(pBuffer != nullptr, "Buffer must not be null"); VERIFY(m_pActiveRenderPass == nullptr, "UpdateBuffer command must be used outside of render pass."); @@ -1228,14 +1258,14 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - CopyBuffer(IBuffer* pSrcBuffer, - Uint32 SrcOffset, - RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode, - IBuffer* pDstBuffer, - Uint32 DstOffset, - Uint32 Size, - RESOURCE_STATE_TRANSITION_MODE DstBufferTransitionMode) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::CopyBuffer( + IBuffer* pSrcBuffer, + Uint32 SrcOffset, + RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode, + IBuffer* pDstBuffer, + Uint32 DstOffset, + Uint32 Size, + RESOURCE_STATE_TRANSITION_MODE DstBufferTransitionMode) { VERIFY(pSrcBuffer != nullptr, "Source buffer must not be null"); VERIFY(pDstBuffer != nullptr, "Destination buffer must not be null"); @@ -1251,8 +1281,11 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - MapBuffer(IBuffer* pBuffer, MAP_TYPE MapType, MAP_FLAGS MapFlags, PVoid& pMappedData) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::MapBuffer( + IBuffer* pBuffer, + MAP_TYPE MapType, + MAP_FLAGS MapFlags, + PVoid& pMappedData) { VERIFY(pBuffer, "pBuffer must not be null"); @@ -1306,8 +1339,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - UnmapBuffer(IBuffer* pBuffer, MAP_TYPE MapType) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::UnmapBuffer(IBuffer* pBuffer, MAP_TYPE MapType) { VERIFY(pBuffer, "pBuffer must not be null"); #ifdef DILIGENT_DEBUG @@ -1322,41 +1354,50 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - UpdateTexture(ITexture* pTexture, Uint32 MipLevel, Uint32 Slice, const Box& DstBox, const TextureSubResData& SubresData, RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode, RESOURCE_STATE_TRANSITION_MODE TextureTransitionMode) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::UpdateTexture( + ITexture* pTexture, + Uint32 MipLevel, + Uint32 Slice, + const Box& DstBox, + const TextureSubResData& SubresData, + RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode, + RESOURCE_STATE_TRANSITION_MODE TextureTransitionMode) { VERIFY(pTexture != nullptr, "pTexture must not be null"); VERIFY(m_pActiveRenderPass == nullptr, "UpdateTexture command must be used outside of render pass."); + ValidateUpdateTextureParams(pTexture->GetDesc(), MipLevel, Slice, DstBox, SubresData); } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - CopyTexture(const CopyTextureAttribs& CopyAttribs) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::CopyTexture(const CopyTextureAttribs& CopyAttribs) { VERIFY(CopyAttribs.pSrcTexture, "Src texture must not be null"); VERIFY(CopyAttribs.pDstTexture, "Dst texture must not be null"); VERIFY(m_pActiveRenderPass == nullptr, "CopyTexture command must be used outside of render pass."); + ValidateCopyTextureParams(CopyAttribs); } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - MapTextureSubresource(ITexture* pTexture, - Uint32 MipLevel, - Uint32 ArraySlice, - MAP_TYPE MapType, - MAP_FLAGS MapFlags, - const Box* pMapRegion, - MappedTextureSubresource& MappedData) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::MapTextureSubresource( + ITexture* pTexture, + Uint32 MipLevel, + Uint32 ArraySlice, + MAP_TYPE MapType, + MAP_FLAGS MapFlags, + const Box* pMapRegion, + MappedTextureSubresource& MappedData) { VERIFY(pTexture, "pTexture must not be null"); ValidateMapTextureParams(pTexture->GetDesc(), MipLevel, ArraySlice, MapType, MapFlags, pMapRegion); } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - UnmapTextureSubresource(ITexture* pTexture, Uint32 MipLevel, Uint32 ArraySlice) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::UnmapTextureSubresource( + ITexture* pTexture, + Uint32 MipLevel, + Uint32 ArraySlice) { VERIFY(pTexture, "pTexture must not be null"); DEV_CHECK_ERR(MipLevel < pTexture->GetDesc().MipLevels, "Mip level is out of range"); @@ -1364,8 +1405,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - GenerateMips(ITextureView* pTexView) +inline void DeviceContextBase<BaseInterface, ImplementationTraits>::GenerateMips(ITextureView* pTexView) { VERIFY(pTexView != nullptr, "pTexView must not be null"); VERIFY(m_pActiveRenderPass == nullptr, "GenerateMips command must be used outside of render pass."); @@ -1382,252 +1422,344 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: template <typename BaseInterface, typename ImplementationTraits> -void DeviceContextBase<BaseInterface, ImplementationTraits>:: - ResolveTextureSubresource(ITexture* pSrcTexture, - ITexture* pDstTexture, - const ResolveTextureSubresourceAttribs& ResolveAttribs) +void DeviceContextBase<BaseInterface, ImplementationTraits>::ResolveTextureSubresource( + ITexture* pSrcTexture, + ITexture* pDstTexture, + const ResolveTextureSubresourceAttribs& ResolveAttribs) { #ifdef DILIGENT_DEVELOPMENT + VERIFY(m_pActiveRenderPass == nullptr, "ResolveTextureSubresource command must be used outside of render pass."); + VERIFY_EXPR(pSrcTexture != nullptr && pDstTexture != nullptr); const auto& SrcTexDesc = pSrcTexture->GetDesc(); const auto& DstTexDesc = pDstTexture->GetDesc(); - DEV_CHECK_ERR(SrcTexDesc.SampleCount > 1, - "Source texture '", SrcTexDesc.Name, "' of a resolve operation is not multi-sampled"); - DEV_CHECK_ERR(DstTexDesc.SampleCount == 1, - "Destination texture '", DstTexDesc.Name, "' of a resolve operation is multi-sampled"); - auto SrcMipLevelProps = GetMipLevelProperties(SrcTexDesc, ResolveAttribs.SrcMipLevel); - auto DstMipLevelProps = GetMipLevelProperties(DstTexDesc, ResolveAttribs.DstMipLevel); - DEV_CHECK_ERR(SrcMipLevelProps.LogicalWidth == DstMipLevelProps.LogicalWidth && SrcMipLevelProps.LogicalHeight == DstMipLevelProps.LogicalHeight, - "The size (", SrcMipLevelProps.LogicalWidth, "x", SrcMipLevelProps.LogicalHeight, - ") of the source subresource of a resolve operation (texture '", - SrcTexDesc.Name, "', mip ", ResolveAttribs.SrcMipLevel, ", slice ", ResolveAttribs.SrcSlice, - ") does not match the size (", DstMipLevelProps.LogicalWidth, "x", DstMipLevelProps.LogicalHeight, - ") of the destination subresource (texture '", DstTexDesc.Name, "', mip ", ResolveAttribs.DstMipLevel, ", slice ", - ResolveAttribs.DstSlice, ")"); - - const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); - const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format); - const auto& ResolveFmtAttribs = GetTextureFormatAttribs(ResolveAttribs.Format); - if (!SrcFmtAttribs.IsTypeless && !DstFmtAttribs.IsTypeless) - { - DEV_CHECK_ERR(SrcTexDesc.Format == DstTexDesc.Format, - "Source (", SrcFmtAttribs.Name, ") and destination (", DstFmtAttribs.Name, - ") texture formats of a resolve operation must match exaclty or be compatible typeless formats"); - DEV_CHECK_ERR(ResolveAttribs.Format == TEX_FORMAT_UNKNOWN || SrcTexDesc.Format == ResolveAttribs.Format, "Invalid format of a resolve operation"); - } - if (SrcFmtAttribs.IsTypeless && DstFmtAttribs.IsTypeless) - { - DEV_CHECK_ERR(ResolveAttribs.Format != TEX_FORMAT_UNKNOWN, - "Format of a resolve operation must not be unknown when both src and dst texture formats are typeless"); - } - if (SrcFmtAttribs.IsTypeless || DstFmtAttribs.IsTypeless) - { - DEV_CHECK_ERR(!ResolveFmtAttribs.IsTypeless, - "Format of a resolve operation must not be typeless when one of the texture formats is typeless"); - } - VERIFY(m_pActiveRenderPass == nullptr, "ResolveTextureSubresource command must be used outside of render pass."); + + VerifyResolveTextureSubresourceAttribs(ResolveAttribs, SrcTexDesc, DstTexDesc); #endif } -#ifdef DILIGENT_DEVELOPMENT + template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyDrawArguments(const DrawAttribs& Attribs) const +bool DeviceContextBase<BaseInterface, ImplementationTraits>::BuildBLAS(const BuildBLASAttribs& Attribs, int) const { - if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) - return true; + if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: ray tracing is not supported by this device"); + return false; + } - if (!m_pPipelineState) + if (m_pActiveRenderPass != nullptr) { - LOG_ERROR_MESSAGE("Draw command arguments are invalid: no pipeline state is bound."); + LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS command must be performed outside of render pass"); return false; } - if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS) + return VerifyBuildBLASAttribs(Attribs); +} + +template <typename BaseInterface, typename ImplementationTraits> +bool DeviceContextBase<BaseInterface, ImplementationTraits>::BuildTLAS(const BuildTLASAttribs& Attribs, int) const +{ + if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) { - LOG_ERROR_MESSAGE("Draw command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); + LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: ray tracing is not supported by this device"); return false; } - if (Attribs.NumVertices == 0) + if (m_pActiveRenderPass != nullptr) { - LOG_WARNING_MESSAGE("Draw command arguments are invalid: number of vertices to draw is zero."); + LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS command must be performed outside of render pass"); + return false; } +#ifdef DILIGENT_DEVELOPMENT + if (!VerifyBuildTLASAttribs(Attribs)) + return false; + + for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) + { + if (!ValidatedCast<BottomLevelASType>(Attribs.pInstances[i].pBLAS)->ValidateContent()) + { + LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances[", i, "].pBLAS is not valid"); + return false; + } + } +#endif + return true; } template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyDrawIndexedArguments(const DrawIndexedAttribs& Attribs) const +bool DeviceContextBase<BaseInterface, ImplementationTraits>::CopyBLAS(const CopyBLASAttribs& Attribs, int) const { - if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) - return true; + if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) + { + LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: ray tracing is not supported by this device"); + return false; + } - if (!m_pPipelineState) + if (m_pActiveRenderPass != nullptr) { - LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: no pipeline state is bound."); + LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS command must be performed outside of render pass"); return false; } - if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS) +#ifdef DILIGENT_DEVELOPMENT + if (!VerifyCopyBLASAttribs(Attribs)) + return false; + + if (!ValidatedCast<BottomLevelASType>(Attribs.pSrc)->ValidateContent()) { - LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: pipeline state '", - m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); + LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: pSrc acceleration structure is not valid"); return false; } +#endif - if (Attribs.IndexType != VT_UINT16 && Attribs.IndexType != VT_UINT32) + return true; +} + +template <typename BaseInterface, typename ImplementationTraits> +bool DeviceContextBase<BaseInterface, ImplementationTraits>::CopyTLAS(const CopyTLASAttribs& Attribs, int) const +{ + if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) { - LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: IndexType (", - GetValueTypeString(Attribs.IndexType), ") must be VT_UINT16 or VT_UINT32."); + LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: ray tracing is not supported by this device"); return false; } - if (!m_pIndexBuffer) + if (m_pActiveRenderPass != nullptr) { - LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: no index buffer is bound."); + LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS command must be performed outside of render pass"); return false; } - if (Attribs.NumIndices == 0) +#ifdef DILIGENT_DEVELOPMENT + if (!VerifyCopyTLASAttribs(Attribs)) + return false; + + if (!ValidatedCast<TopLevelASType>(Attribs.pSrc)->ValidateContent()) { - LOG_WARNING_MESSAGE("DrawIndexed command arguments are invalid: number of indices to draw is zero."); + LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pSrc acceleration structure is not valid"); + return false; } +#endif return true; } template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyDrawMeshArguments(const DrawMeshAttribs& Attribs) const +bool DeviceContextBase<BaseInterface, ImplementationTraits>::WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs, int) const { - if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) - return true; + if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) + { + LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: ray tracing is not supported by this device"); + return false; + } - if (m_pDevice->GetDeviceCaps().Features.MeshShaders != DEVICE_FEATURE_STATE_ENABLED) + if (m_pActiveRenderPass != nullptr) { - LOG_ERROR_MESSAGE("DrawMesh: mesh shaders are not supported by this device"); + LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: command must be performed outside of render pass"); return false; } - if (!m_pPipelineState) +#ifdef DILIGENT_DEVELOPMENT + if (!VerifyWriteBLASCompactedSizeAttribs(m_pDevice, Attribs)) + return false; +#endif + + return true; +} + +template <typename BaseInterface, typename ImplementationTraits> +bool DeviceContextBase<BaseInterface, ImplementationTraits>::WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs, int) const +{ + if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) { - LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: no pipeline state is bound."); + LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: ray tracing is not supported by this device"); return false; } - if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_MESH) + if (m_pActiveRenderPass != nullptr) { - LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: pipeline state '", - m_pPipelineState->GetDesc().Name, "' is not a mesh pipeline."); + LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: command must be performed outside of render pass"); + return false; + } + +#ifdef DILIGENT_DEVELOPMENT + if (!VerifyWriteTLASCompactedSizeAttribs(m_pDevice, Attribs)) + return false; +#endif + + return true; +} + +template <typename BaseInterface, typename ImplementationTraits> +bool DeviceContextBase<BaseInterface, ImplementationTraits>::TraceRays(const TraceRaysAttribs& Attribs, int) const +{ + if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) + { + LOG_ERROR_MESSAGE("IDeviceContext::TraceRays: ray tracing is not supported by this device"); return false; } - if (Attribs.ThreadGroupCount == 0) + if (!m_pPipelineState) { - LOG_WARNING_MESSAGE("DrawMesh command arguments are invalid: number of groups to dispatch is zero."); + LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: no pipeline state is bound."); + return false; } - if (Attribs.ThreadGroupCount > m_pDevice->GetProperties().MaxDrawMeshTasksCount) + if (!m_pPipelineState->GetDesc().IsRayTracingPipeline()) { - LOG_WARNING_MESSAGE("DrawMesh command arguments are invalid: number of groups to dispatch must be less then ", m_pDevice->GetProperties().MaxDrawMeshTasksCount); + LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a ray tracing pipeline."); + return false; } +#ifdef DILIGENT_DEVELOPMENT + if (!VerifyTraceRaysAttribs(Attribs)) + return false; +#endif + return true; } + + + +#ifdef DILIGENT_DEVELOPMENT + template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyDrawIndirectArguments(const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawArguments(const DrawAttribs& Attribs) const { if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) return true; if (!m_pPipelineState) { - LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: no pipeline state is bound."); + LOG_ERROR_MESSAGE("Draw command arguments are invalid: no pipeline state is bound."); return false; } if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS) { + LOG_ERROR_MESSAGE("Draw command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); + return false; + } - LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: pipeline state '", + return VerifyDrawAttribs(Attribs); +} + +template <typename BaseInterface, typename ImplementationTraits> +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawIndexedArguments(const DrawIndexedAttribs& Attribs) const +{ + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) + return true; + + if (!m_pPipelineState) + { + LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: no pipeline state is bound."); + return false; + } + + if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS) + { + LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); return false; } - if (pAttribsBuffer != nullptr) + if (!m_pIndexBuffer) { - if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0) - { - LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: indirect draw arguments buffer '", - pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); - return false; - } + LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: no index buffer is bound."); + return false; } - else + + return VerifyDrawIndexedAttribs(Attribs); +} + +template <typename BaseInterface, typename ImplementationTraits> +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawMeshArguments(const DrawMeshAttribs& Attribs) const +{ + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) + return true; + + if (m_pDevice->GetDeviceCaps().Features.MeshShaders != DEVICE_FEATURE_STATE_ENABLED) { - LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: indirect draw arguments buffer is null."); + LOG_ERROR_MESSAGE("DrawMesh: mesh shaders are not supported by this device"); return false; } - if (m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + if (!m_pPipelineState) { - LOG_ERROR_MESSAGE("Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " - "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); + LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: no pipeline state is bound."); return false; } - return true; + if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_MESH) + { + LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: pipeline state '", + m_pPipelineState->GetDesc().Name, "' is not a mesh pipeline."); + return false; + } + + return VerifyDrawMeshAttribs(m_pDevice->GetProperties().MaxDrawMeshTasksCount, Attribs); } template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyDrawIndexedIndirectArguments(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawIndirectArguments( + const DrawIndirectAttribs& Attribs, + const IBuffer* pAttribsBuffer) const { if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) return true; if (!m_pPipelineState) { - LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: no pipeline state is bound."); + LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: no pipeline state is bound."); return false; } if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS) { - LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: pipeline state '", + + LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); return false; } - if (Attribs.IndexType != VT_UINT16 && Attribs.IndexType != VT_UINT32) + if (m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { - LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: IndexType (", - GetValueTypeString(Attribs.IndexType), ") must be VT_UINT16 or VT_UINT32."); + LOG_ERROR_MESSAGE("Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); return false; } - if (!m_pIndexBuffer) + return VerifyDrawIndirectAttribs(Attribs, pAttribsBuffer); +} + +template <typename BaseInterface, typename ImplementationTraits> +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawIndexedIndirectArguments( + const DrawIndexedIndirectAttribs& Attribs, + const IBuffer* pAttribsBuffer) const +{ + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) + return true; + + if (!m_pPipelineState) { - LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: no index buffer is bound."); + LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: no pipeline state is bound."); return false; } - if (pAttribsBuffer != nullptr) + if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS) { - if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0) - { - LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: indirect draw arguments buffer '", - pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); - return false; - } + LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: pipeline state '", + m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); + return false; } - else + + if (!m_pIndexBuffer) { - LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: indirect draw arguments buffer is null."); + LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: no index buffer is bound."); return false; } @@ -1638,12 +1770,13 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: return false; } - return true; + return VerifyDrawIndexedIndirectAttribs(Attribs, pAttribsBuffer); } template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyDrawMeshIndirectArguments(const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawMeshIndirectArguments( + const DrawMeshIndirectAttribs& Attribs, + const IBuffer* pAttribsBuffer) const { if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) return true; @@ -1667,39 +1800,23 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: return false; } - if (pAttribsBuffer != nullptr) - { - if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0) - { - LOG_ERROR_MESSAGE("DrawMeshIndirect command arguments are invalid: indirect draw arguments buffer '", - pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); - return false; - } - } - else - { - LOG_ERROR_MESSAGE("DrawMeshIndirect command arguments are invalid: indirect draw arguments buffer is null."); - return false; - } - - return true; + return VerifyDrawMeshIndirectAttribs(Attribs, pAttribsBuffer); } template <typename BaseInterface, typename ImplementationTraits> -inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyRenderTargets() const +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyRenderTargets() const { if (!m_pPipelineState) { LOG_ERROR_MESSAGE("No pipeline state is bound"); - return; + return false; } const auto& PSODesc = m_pPipelineState->GetDesc(); if (!PSODesc.IsAnyGraphicsPipeline()) { LOG_ERROR_MESSAGE("Pipeline state '", PSODesc.Name, "' is not a graphics pipeline"); - return; + return false; } TEXTURE_FORMAT BoundRTVFormats[8] = {TEX_FORMAT_UNKNOWN}; @@ -1741,13 +1858,14 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: "' (", GetTextureFormatAttribs(PSOFmt).Name, ")."); } } + + return true; } template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyDispatchArguments(const DispatchComputeAttribs& Attribs) const +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDispatchArguments(const DispatchComputeAttribs& Attribs) const { if (!m_pPipelineState) { @@ -1768,21 +1886,13 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: return false; } - if (Attribs.ThreadGroupCountX == 0) - LOG_WARNING_MESSAGE("DispatchCompute command arguments are invalid: ThreadGroupCountX is zero."); - - if (Attribs.ThreadGroupCountY == 0) - LOG_WARNING_MESSAGE("DispatchCompute command arguments are invalid: ThreadGroupCountY is zero."); - - if (Attribs.ThreadGroupCountZ == 0) - LOG_WARNING_MESSAGE("DispatchCompute command arguments are invalid: ThreadGroupCountZ is zero."); - - return true; + return VerifyDispatchComputeAttribs(Attribs); } template <typename BaseInterface, typename ImplementationTraits> -inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const +inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDispatchIndirectArguments( + const DispatchComputeIndirectAttribs& Attribs, + const IBuffer* pAttribsBuffer) const { if (!m_pPipelineState) { @@ -1803,114 +1913,21 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>:: return false; } - if (pAttribsBuffer != nullptr) - { - if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0) - { - LOG_ERROR_MESSAGE("DispatchComputeIndirect command arguments are invalid: indirect dispatch arguments buffer '", - pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); - return false; - } - } - else - { - LOG_ERROR_MESSAGE("DispatchComputeIndirect command arguments are invalid: indirect dispatch arguments buffer is null."); - return false; - } - - return true; + return VerifyDispatchComputeIndirectAttribs(Attribs, pAttribsBuffer); } template <typename BaseInterface, typename ImplementationTraits> -void DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier) const +bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier) const { - 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 (RefCntAutoPtr<ITexture> pTexture{Barrier.pResource, IID_Texture}) - { - 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 : 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"); - DEV_CHECK_ERR(VerifyResourceStates(OldState, true), "Invlaid old state specified for texture '", TexDesc.Name, "'"); - - DEV_CHECK_ERR(Barrier.FirstMipLevel < TexDesc.MipLevels, "First mip level (", Barrier.FirstMipLevel, - ") specified by the barrier is out of range. Texture '", - TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)"); - DEV_CHECK_ERR(Barrier.MipLevelsCount == REMAINING_MIP_LEVELS || Barrier.FirstMipLevel + Barrier.MipLevelsCount <= TexDesc.MipLevels, - "Mip level range ", Barrier.FirstMipLevel, "..", Barrier.FirstMipLevel + Barrier.MipLevelsCount - 1, - " specified by the barrier is out of range. Texture '", - TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)"); - - DEV_CHECK_ERR(Barrier.FirstArraySlice < TexDesc.ArraySize, "First array slice (", Barrier.FirstArraySlice, - ") specified by the barrier is out of range. Array size of texture '", - TexDesc.Name, "' is ", TexDesc.ArraySize); - DEV_CHECK_ERR(Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES || Barrier.FirstArraySlice + Barrier.ArraySliceCount <= TexDesc.ArraySize, - "Array slice range ", Barrier.FirstArraySlice, "..", Barrier.FirstArraySlice + Barrier.ArraySliceCount - 1, - " specified by the barrier is out of range. Array size of texture '", - TexDesc.Name, "' is ", TexDesc.ArraySize); - - auto DevType = m_pDevice->GetDeviceCaps().DevType; - if (DevType != RENDER_DEVICE_TYPE_D3D12 && DevType != RENDER_DEVICE_TYPE_VULKAN) - { - DEV_CHECK_ERR(Barrier.FirstMipLevel == 0 && (Barrier.MipLevelsCount == REMAINING_MIP_LEVELS || Barrier.MipLevelsCount == TexDesc.MipLevels), - "Failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device"); - DEV_CHECK_ERR(Barrier.FirstArraySlice == 0 && (Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES || Barrier.ArraySliceCount == TexDesc.ArraySize), - "Failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device"); - } - } - else if (RefCntAutoPtr<IBuffer> pBuffer{Barrier.pResource, IID_Buffer}) - { - 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 : 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 if (RefCntAutoPtr<IBottomLevelAS> pBottomLevelAS{Barrier.pResource, IID_BottomLevelAS}) - { - const auto& BLASDesc = pBottomLevelAS->GetDesc(); - OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pBottomLevelAS->GetState(); - DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of BLAS '", BLASDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); - DEV_CHECK_ERR(Barrier.NewState == RESOURCE_STATE_BUILD_AS_READ || Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE, - "Invlaid new state specified for BLAS '", BLASDesc.Name, "'"); - DEV_CHECK_ERR(Barrier.TransitionType != STATE_TRANSITION_TYPE_IMMEDIATE, "Split barriers are not supported for BLAS"); - } - else if (RefCntAutoPtr<ITopLevelAS> pTopLevelAS{Barrier.pResource, IID_TopLevelAS}) - { - const auto& TLASDesc = pTopLevelAS->GetDesc(); - OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pTopLevelAS->GetState(); - DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of TLAS '", TLASDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); - DEV_CHECK_ERR(Barrier.NewState == RESOURCE_STATE_BUILD_AS_READ || Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE || Barrier.NewState == RESOURCE_STATE_RAY_TRACING, - "Invlaid new state specified for TLAS '", TLASDesc.Name, "'"); - DEV_CHECK_ERR(Barrier.TransitionType != STATE_TRANSITION_TYPE_IMMEDIATE, "Split barriers are not supported for TLAS"); - } - else - { - UNEXPECTED("unsupported resource type"); - } - - if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS) - { - DEV_CHECK_ERR(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE, "For UAV barriers, transition type must be STATE_TRANSITION_TYPE_IMMEDIATE"); - } - - if (Barrier.TransitionType == STATE_TRANSITION_TYPE_BEGIN) - { - DEV_CHECK_ERR(!Barrier.UpdateResourceState, "Resource state can't be updated in begin-split barrier"); - } + return VerifyStateTransitionDesc(m_pDevice, Barrier); } template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName) const +bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyTextureState( + const TextureImplType& Texture, + RESOURCE_STATE RequiredState, + const char* OperationName) const { if (Texture.IsInKnownState() && !Texture.CheckState(RequiredState)) { @@ -1924,8 +1941,10 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>:: } template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyBufferState(const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName) const +bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyBufferState( + const BufferImplType& Buffer, + RESOURCE_STATE RequiredState, + const char* OperationName) const { if (Buffer.IsInKnownState() && !Buffer.CheckState(RequiredState)) { @@ -1939,8 +1958,10 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>:: } template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyBLASState(const BottomLevelASType& BLAS, RESOURCE_STATE RequiredState, const char* OperationName) const +bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyBLASState( + const BottomLevelASType& BLAS, + RESOURCE_STATE RequiredState, + const char* OperationName) const { if (BLAS.IsInKnownState() && !BLAS.CheckState(RequiredState)) { @@ -1954,8 +1975,10 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>:: } template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>:: - DvpVerifyTLASState(const TopLevelASType& TLAS, RESOURCE_STATE RequiredState, const char* OperationName) const +bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyTLASState( + const TopLevelASType& TLAS, + RESOURCE_STATE RequiredState, + const char* OperationName) const { if (TLAS.IsInKnownState() && !TLAS.CheckState(RequiredState)) { @@ -1967,723 +1990,7 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>:: return true; } -#endif // DILIGENT_DEVELOPMENT - -template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>::BuildBLAS(const BuildBLASAttribs& Attribs, int) const -{ - if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: ray tracing is not supported by this device"); - return false; - } - - if (m_pActiveRenderPass != nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS command must be performed outside of render pass"); - return false; - } - - if (Attribs.pBLAS == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBLAS must not be null"); - return false; - } - - if (Attribs.pScratchBuffer == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pScratchBuffer must not be null"); - return false; - } - - if (!((Attribs.pTriangleData != nullptr) ^ (Attribs.pBoxData != nullptr))) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: exactly one of pTriangles and pBoxes must be defined"); - return false; - } - - if (Attribs.pBoxData == nullptr && Attribs.BoxDataCount > 0) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBoxData is null but BoxDataCount is not 0"); - return false; - } - - if (Attribs.pTriangleData == nullptr && Attribs.TriangleDataCount > 0) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData is null but TriangleDataCount is not 0"); - return false; - } - - const auto& BLASDesc = Attribs.pBLAS->GetDesc(); - - if (Attribs.BoxDataCount > BLASDesc.BoxCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: BoxDataCount must be less than or equal to pBLAS->GetDesc().BoxCount"); - return false; - } - - if (Attribs.TriangleDataCount > BLASDesc.TriangleCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: TriangleDataCount must be less than or equal to pBLAS->GetDesc().TriangleCount"); - return false; - } - -#ifdef DILIGENT_DEVELOPMENT - for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i) - { - const auto& tri = Attribs.pTriangleData[i]; - const Uint32 VertexSize = GetValueSize(tri.VertexValueType) * tri.VertexComponentCount; - const Uint32 VertexDataSize = tri.VertexStride * tri.VertexCount; - const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryIndex(tri.GeometryName); - - if (GeomIndex == BottomLevelASType::InvalidGeometryIndex) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].GeometryName not found in BLAS description"); - return false; - } - - const auto& TriDesc = BLASDesc.pTriangles[GeomIndex]; - - if (tri.VertexValueType != VT_UNDEFINED && tri.VertexValueType != TriDesc.VertexValueType) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].VertexValueType must be undefined or match the VertexValueType in geometry description"); - return false; - } - - if (tri.VertexComponentCount != 0 && tri.VertexComponentCount != TriDesc.VertexComponentCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].VertexComponentCount must be 0 or match the VertexComponentCount in geometry description"); - return false; - } - - if (tri.VertexCount > TriDesc.MaxVertexCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].VertexCount must not be greater then MaxVertexCount(", TriDesc.MaxVertexCount, ")"); - 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 ((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 (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 && tri.IndexType != TriDesc.IndexType) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].IndexType must match the IndexType in geometry description"); - return false; - } - - if (tri.PrimitiveCount > TriDesc.MaxPrimitiveCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].PrimitiveCount must not be greater then MaxPrimitiveCount(", TriDesc.MaxPrimitiveCount, ")"); - return false; - } - - if (TriDesc.IndexType != VT_UNDEFINED) - { - if (tri.pIndexBuffer == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].pIndexBuffer must not be null"); - return false; - } - - 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.PrimitiveCount * 3 * 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 - { - if (tri.VertexCount != tri.PrimitiveCount * 3) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "].VertexCount must equal to (PrimitiveCount * 3)"); - return false; - } - - VERIFY(tri.pIndexBuffer == nullptr, - "IDeviceContext::BuildBLAS: pTriangleData[", i, "].pIndexBuffer must be null if IndexType is VT_UNDEFINED"); - } - - if (tri.pTransformBuffer != nullptr) - { - 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; - } - - if (!TriDesc.AllowsTransforms) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pTriangleData[", i, "] use transform buffer but AllowsTransforms is false"); - return false; - } - } - } - - for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i) - { - const auto& box = Attribs.pBoxData[i]; - const Uint32 BoxSize = sizeof(float) * 6; - const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryIndex(box.GeometryName); - - if (GeomIndex == BottomLevelASType::InvalidGeometryIndex) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBoxData[", i, "].GeometryName not found in BLAS description"); - return false; - } - - const auto& BoxDesc = BLASDesc.pBoxes[GeomIndex]; - - if (box.BoxCount > BoxDesc.MaxBoxCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pBoxData[", i, "].BoxCount must not be greated then MaxBoxCount (", BoxDesc.MaxBoxCount, ")"); - return false; - } - - 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 ((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; - } - } -#endif // DILIGENT_DEVELOPMENT - - const auto& ScratchDesc = Attribs.pScratchBuffer->GetDesc(); - - if (Attribs.ScratchBufferOffset > ScratchDesc.uiSizeInBytes) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: ScratchBufferOffset is greater than buffer size"); - return false; - } - - if (ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset < Attribs.pBLAS->GetScratchBufferSizes().Build) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: pScratchBuffer size is too small, use pBLAS->GetScratchBufferSizes().Build to get required size for scratch buffer"); - return false; - } - - if ((ScratchDesc.BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must be created with BIND_RAY_TRACING flag"); - return false; - } - - return true; -} - -template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>::BuildTLAS(const BuildTLASAttribs& Attribs, int) const -{ - if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: ray tracing is not supported by this device"); - return false; - } - - if (m_pActiveRenderPass != nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS command must be performed outside of render pass"); - return false; - } - - if (Attribs.pTLAS == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pTLAS must not be null"); - return false; - } - - if (Attribs.pScratchBuffer == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must not be null"); - return false; - } - - if (Attribs.pInstances == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances must not be null"); - return false; - } - - if (Attribs.pInstanceBuffer == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceBuffer must not be null"); - return false; - } - - if (Attribs.HitShadersPerInstance == 0) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: HitShadersPerInstance must be greater than 0"); - return false; - } - - const auto& TLASDesc = Attribs.pTLAS->GetDesc(); - - if (Attribs.InstanceCount > TLASDesc.MaxInstanceCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: InstanceCount must be less than or equal to Attribs.pTLAS->GetDesc().MaxInstanceCount"); - return false; - } - - const auto& InstDesc = Attribs.pInstanceBuffer->GetDesc(); - const size_t InstDataSize = Attribs.InstanceCount * TLAS_INSTANCE_DATA_SIZE; - -#ifdef DILIGENT_DEVELOPMENT - Uint32 AutoOffsetCounter = 0; - - // calculate instance data size - for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) - { - VERIFY((Attribs.pInstances[i].CustomId & ~0x00FFFFFF) == 0, "Only the lower 24 bits are used"); - - VERIFY(Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO || - (Attribs.pInstances[i].ContributionToHitGroupIndex & ~0x00FFFFFF) == 0, - "Only the lower 24 bits are used"); - - if (Attribs.pInstances[i].InstanceName == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances[", i, "].InstanceName must not be null"); - return false; - } - - if (Attribs.pInstances[i].pBLAS == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances[", i, "].pBLAS must not be null"); - return false; - } - - if (!ValidatedCast<BottomLevelASType>(Attribs.pInstances[i].pBLAS)->ValidateContent()) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances[", i, "].pBLAS is not valid"); - return false; - } - - if (Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) - ++AutoOffsetCounter; - - - if (TLASDesc.BindingMode != SHADER_BINDING_USER_DEFINED && Attribs.pInstances[i].ContributionToHitGroupIndex != TLAS_INSTANCE_OFFSET_AUTO) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstances[", i, - "].ContributionToHitGroupIndex must be TLAS_INSTANCE_OFFSET_AUTO " - "if TLAS created with BindingMode that is not SHADER_BINDING_USER_DEFINED"); - return false; - } - } - - 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; - } -#endif // DILIGENT_DEVELOPMENT - - if (Attribs.InstanceBufferOffset > InstDesc.uiSizeInBytes) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: InstanceBufferOffset is greater than buffer size"); - return false; - } - - if (InstDesc.uiSizeInBytes - Attribs.InstanceBufferOffset < InstDataSize) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceBuffer size is too small, ..."); - return false; - } - - if ((InstDesc.BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pInstanceBuffer must be created with BIND_RAY_TRACING flag"); - return false; - } - - const auto& ScratchDesc = Attribs.pScratchBuffer->GetDesc(); - - if (Attribs.ScratchBufferOffset > ScratchDesc.uiSizeInBytes) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: ScratchBufferOffset is greater than buffer size"); - return false; - } - - if (ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset < Attribs.pTLAS->GetScratchBufferSizes().Build) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer size is too small, use pTLAS->GetScratchBufferSizes().Build to get required size for scratch buffer"); - return false; - } - - if ((ScratchDesc.BindFlags & BIND_RAY_TRACING) != BIND_RAY_TRACING) - { - LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: pScratchBuffer must be created with BIND_RAY_TRACING flag"); - return false; - } - - return true; -} - -template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>::CopyBLAS(const CopyBLASAttribs& Attribs, int) const -{ - if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: ray tracing is not supported by this device"); - return false; - } - - if (Attribs.pSrc == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: pSrc must not be null"); - return false; - } - - if (Attribs.pDst == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: pDst must not be null"); - return false; - } - - if (m_pActiveRenderPass != nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS command must be performed outside of render pass"); - return false; - } - -#ifdef DILIGENT_DEVELOPMENT - if (!ValidatedCast<BottomLevelASType>(Attribs.pSrc)->ValidateContent()) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: pSrc acceleration structure is not valid"); - return false; - } - - if (Attribs.Mode == COPY_AS_MODE_CLONE) - { - auto& SrcDesc = Attribs.pSrc->GetDesc(); - auto& DstDesc = Attribs.pDst->GetDesc(); - - if (SrcDesc.TriangleCount != DstDesc.TriangleCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different TriangleCount, pDst must have been created with the same parameters as pSrc"); - return false; - } - - if (SrcDesc.BoxCount != DstDesc.BoxCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different BoxCount, pDst must have been created with the same parameters as pSrc"); - return false; - } - - if (SrcDesc.Flags != DstDesc.Flags) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different Flags, pDst must have been created with the same parameters as pSrc"); - return false; - } - - for (Uint32 i = 0; i < SrcDesc.TriangleCount; ++i) - { - auto& SrcTri = SrcDesc.pTriangles[i]; - auto& DstTri = DstDesc.pTriangles[i]; - - // clang-format off - if (SrcTri.MaxVertexCount != DstTri.MaxVertexCount || - SrcTri.VertexValueType != DstTri.VertexValueType || - SrcTri.VertexComponentCount != DstTri.VertexComponentCount || - SrcTri.MaxPrimitiveCount != DstTri.MaxPrimitiveCount || - SrcTri.IndexType != DstTri.IndexType || - SrcTri.AllowsTransforms != DstTri.AllowsTransforms) - // clang-format on - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different triangle descriptions at index: ", i, ", pDst must have been created with the same parameters as pSrc"); - return false; - } - } - - for (Uint32 i = 0; i < SrcDesc.BoxCount; ++i) - { - if (SrcDesc.pBoxes[i].MaxBoxCount != DstDesc.pBoxes[i].MaxBoxCount) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: different box descriptions at index: ", i, ", pDst must have been created with the same parameters as pSrc"); - return false; - } - } - } - else if (Attribs.Mode == COPY_AS_MODE_COMPACT) - { - auto& SrcDesc = Attribs.pSrc->GetDesc(); - auto& DstDesc = Attribs.pDst->GetDesc(); - - if (!(SrcDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION)) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: pSrc must be create with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); - return false; - } - - if (DstDesc.CompactedSize == 0) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: pDst must be create with defined CompactedSize"); - return false; - } - } - else - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: unknown Mode"); - return false; - } -#endif // DILIGENT_DEVELOPMENT - - return true; -} - -template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>::CopyTLAS(const CopyTLASAttribs& Attribs, int) const -{ - if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: ray tracing is not supported by this device"); - return false; - } - - if (Attribs.pSrc == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pSrc must not be null"); - return false; - } - - if (Attribs.pDst == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pDst must not be null"); - return false; - } - - if (m_pActiveRenderPass != nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS command must be performed outside of render pass"); - return false; - } - -#ifdef DILIGENT_DEVELOPMENT - if (!ValidatedCast<TopLevelASType>(Attribs.pSrc)->ValidateContent()) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pSrc acceleration structure is not valid"); - return false; - } - - if (Attribs.Mode == COPY_AS_MODE_CLONE) - { - auto& SrcDesc = Attribs.pSrc->GetDesc(); - auto& DstDesc = Attribs.pDst->GetDesc(); - - if (SrcDesc.MaxInstanceCount != DstDesc.MaxInstanceCount || - SrcDesc.Flags != DstDesc.Flags) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pDst must have been created with the same parameters as pSrc"); - return false; - } - } - else if (Attribs.Mode == COPY_AS_MODE_COMPACT) - { - auto& SrcDesc = Attribs.pSrc->GetDesc(); - auto& DstDesc = Attribs.pDst->GetDesc(); - - if (!(SrcDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION)) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pSrc must be create with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); - return false; - } - - if (DstDesc.CompactedSize == 0) - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pDst must be create with defined CompactedSize"); - return false; - } - } - else - { - LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: unknown Mode"); - return false; - } -#endif // DILIGENT_DEVELOPMENT - - return true; -} - -template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>::WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs, int) const -{ - if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: ray tracing is not supported by this device"); - return false; - } - - if (Attribs.pBLAS == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: pBLAS must not be null"); - return false; - } - if (!(Attribs.pBLAS->GetDesc().Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION)) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: pBLAS must be created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); - return false; - } - - if (Attribs.pDestBuffer == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: pDestBuffer must not be null"); - return false; - } - if (Attribs.DestBufferOffset + sizeof(Uint64) > Attribs.pDestBuffer->GetDesc().uiSizeInBytes) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: pDestBuffer is too small"); - return false; - } - if (m_pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_D3D12 && - !(Attribs.pDestBuffer->GetDesc().BindFlags & BIND_UNORDERED_ACCESS)) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: pDestBuffer must be created with BIND_UNORDERED_ACCESS flag"); - return false; - } - - if (m_pActiveRenderPass != nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: command must be performed outside of render pass"); - return false; - } - return true; -} - -template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>::WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs, int) const -{ - if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: ray tracing is not supported by this device"); - return false; - } - - if (Attribs.pTLAS == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: pTLAS must not be null"); - return false; - } - if (!(Attribs.pTLAS->GetDesc().Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION)) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: pTLAS must be created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); - return false; - } - - if (Attribs.pDestBuffer == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: pDestBuffer must not be null"); - return false; - } - if (Attribs.DestBufferOffset + sizeof(Uint64) > Attribs.pDestBuffer->GetDesc().uiSizeInBytes) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: pDestBuffer is too small"); - return false; - } - if (m_pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_D3D12 && - !(Attribs.pDestBuffer->GetDesc().BindFlags & BIND_UNORDERED_ACCESS)) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: pDestBuffer must be created with BIND_UNORDERED_ACCESS flag"); - return false; - } - - if (m_pActiveRenderPass != nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: command must be performed outside of render pass"); - return false; - } - return true; -} - -template <typename BaseInterface, typename ImplementationTraits> -bool DeviceContextBase<BaseInterface, ImplementationTraits>::TraceRays(const TraceRaysAttribs& Attribs, int) const -{ - if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED) - { - LOG_ERROR_MESSAGE("IDeviceContext::TraceRays: ray tracing is not supported by this device"); - return false; - } - - if (Attribs.pSBT == nullptr) - { - LOG_ERROR_MESSAGE("IDeviceContext::TraceRays: pSBT must not be null"); - return false; - } - -#ifdef DILIGENT_DEVELOPMENT - if (!Attribs.pSBT->Verify()) - { - LOG_ERROR_MESSAGE("IDeviceContext::TraceRays: pSBT content is not valid"); - return false; - } #endif // DILIGENT_DEVELOPMENT - if (!m_pPipelineState) - { - LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: no pipeline state is bound."); - return false; - } - - if (!m_pPipelineState->GetDesc().IsRayTracingPipeline()) - { - LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a ray tracing pipeline."); - return false; - } - - if (Attribs.pSBT->GetDesc().pPSO != m_pPipelineState.RawPtr()) - { - LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: currently bound pipeline ", m_pPipelineState->GetDesc().Name, - "doesn't match the pipeline ", Attribs.pSBT->GetDesc().pPSO->GetDesc().Name, " that was used in ShaderBindingTable"); - return false; - } - - if (Attribs.DimensionX == 0) - LOG_WARNING_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: DimensionX is zero."); - - if (Attribs.DimensionY == 0) - LOG_WARNING_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: DimensionY is zero."); - - if (Attribs.DimensionZ == 0) - LOG_WARNING_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: DimensionZ is zero."); - - return true; -} - } // namespace Diligent diff --git a/Graphics/GraphicsEngine/include/FramebufferBase.hpp b/Graphics/GraphicsEngine/include/FramebufferBase.hpp index ca386375..0cd484dc 100644 --- a/Graphics/GraphicsEngine/include/FramebufferBase.hpp +++ b/Graphics/GraphicsEngine/include/FramebufferBase.hpp @@ -39,7 +39,7 @@ namespace Diligent { -void ValidateFramebufferDesc(const FramebufferDesc& Desc); +void ValidateFramebufferDesc(const FramebufferDesc& Desc) noexcept(false); /// Template class implementing base functionality for the framebuffer object. diff --git a/Graphics/GraphicsEngine/interface/BottomLevelAS.h b/Graphics/GraphicsEngine/interface/BottomLevelAS.h index cfabc1d5..bd80e3e4 100644 --- a/Graphics/GraphicsEngine/interface/BottomLevelAS.h +++ b/Graphics/GraphicsEngine/interface/BottomLevelAS.h @@ -178,6 +178,7 @@ struct ScratchBufferSizes }; typedef struct ScratchBufferSizes ScratchBufferSizes; +static const Uint32 InvalidGeometryIndex = ~0u; #define DILIGENT_INTERFACE_NAME IBottomLevelAS #include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" diff --git a/Graphics/GraphicsEngine/src/DeviceContextBase.cpp b/Graphics/GraphicsEngine/src/DeviceContextBase.cpp new file mode 100644 index 00000000..a526bd37 --- /dev/null +++ b/Graphics/GraphicsEngine/src/DeviceContextBase.cpp @@ -0,0 +1,704 @@ +/* + * 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 "DeviceContextBase.hpp" +#include "GraphicsAccessories.hpp" + +namespace Diligent +{ + +#if DILIGENT_DEBUG + +# define CHECK_PARAMETER(Expr, ...) \ + do \ + { \ + VERIFY(Expr, __VA_ARGS__); \ + if (!(Expr)) return false; \ + } while (false) + +#else + +# define CHECK_PARAMETER(Expr, ...) \ + do \ + { \ + if (!(Expr)) \ + { \ + LOG_ERROR_MESSAGE(__VA_ARGS__); \ + return false; \ + } \ + } while (false) + +#endif + +bool VerifyDrawAttribs(const DrawAttribs& Attribs) +{ +#define CHECK_DRAW_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw attribs are invalid: ", __VA_ARGS__) + + CHECK_DRAW_ATTRIBS(Attribs.NumVertices != 0, "NumVertices must not be zero."); + +#undef CHECK_DRAW_ATTRIBS + + return true; +} + +bool VerifyDrawIndexedAttribs(const DrawIndexedAttribs& Attribs) +{ +#define CHECK_DRAW_INDEXED_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw indexed attribs are invalid: ", __VA_ARGS__) + + CHECK_DRAW_INDEXED_ATTRIBS(Attribs.IndexType == VT_UINT16 || Attribs.IndexType == VT_UINT32, + "IndexType (", GetValueTypeString(Attribs.IndexType), ") must be VT_UINT16 or VT_UINT32."); + + CHECK_DRAW_INDEXED_ATTRIBS(Attribs.NumIndices != 0, "NumIndices must not be zero."); + +#undef CHECK_DRAW_INDEXED_ATTRIBS + + return true; +} + +bool VerifyDrawMeshAttribs(Uint32 MaxDrawMeshTasksCount, const DrawMeshAttribs& Attribs) +{ +#define CHECK_DRAW_MESH_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw mesh attribs are invalid: ", __VA_ARGS__) + + CHECK_DRAW_MESH_ATTRIBS(Attribs.ThreadGroupCount != 0, "ThreadGroupCount must not be zero."); + CHECK_DRAW_MESH_ATTRIBS(Attribs.ThreadGroupCount <= MaxDrawMeshTasksCount, + "ThreadGroupCount (", Attribs.ThreadGroupCount, ") must not exceed ", MaxDrawMeshTasksCount); + +#undef CHECK_DRAW_MESH_ATTRIBS + + return true; +} + +bool VerifyDrawIndirectAttribs(const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) +{ +#define CHECK_DRAW_INDIRECT_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw indirect attribs are invalid: ", __VA_ARGS__) + + CHECK_DRAW_INDIRECT_ATTRIBS(pAttribsBuffer != nullptr, "indirect draw arguments buffer must not be null."); + CHECK_DRAW_INDIRECT_ATTRIBS((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) != 0, + "indirect draw arguments buffer '", pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); + +#undef CHECK_DRAW_INDIRECT_ATTRIBS + + return true; +} + +bool VerifyDrawIndexedIndirectAttribs(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) +{ +#define CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw indexed indirect attribs are invalid: ", __VA_ARGS__) + + CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS(pAttribsBuffer != nullptr, "indirect draw arguments buffer must not null."); + CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS(Attribs.IndexType == VT_UINT16 || Attribs.IndexType == VT_UINT32, + "IndexType (", GetValueTypeString(Attribs.IndexType), ") must be VT_UINT16 or VT_UINT32."); + CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) != 0, + "indirect draw arguments buffer '", + pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); + +#undef CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS + + return true; +} + +bool VerifyDrawMeshIndirectAttribs(const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) +{ +#define CHECK_DRAW_MESH_INDIRECT_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw mesh indirect attribs are invalid: ", __VA_ARGS__) + + CHECK_DRAW_MESH_INDIRECT_ATTRIBS(pAttribsBuffer != nullptr, "indirect draw arguments buffer must not be null."); + CHECK_DRAW_MESH_INDIRECT_ATTRIBS((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) != 0, + "indirect draw arguments buffer '", pAttribsBuffer->GetDesc().Name, + "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); + +#undef CHECK_DRAW_MESH_INDIRECT_ATTRIBS + + return true; +} + + +bool VerifyDispatchComputeAttribs(const DispatchComputeAttribs& Attribs) +{ +#define CHECK_DISPATCH_COMPUTE_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Dispatch compute attribs are invalid: ", __VA_ARGS__) + + CHECK_DISPATCH_COMPUTE_ATTRIBS(Attribs.ThreadGroupCountX != 0, "ThreadGroupCountX must no be zero."); + CHECK_DISPATCH_COMPUTE_ATTRIBS(Attribs.ThreadGroupCountY != 0, "ThreadGroupCountY must no be zero."); + CHECK_DISPATCH_COMPUTE_ATTRIBS(Attribs.ThreadGroupCountZ != 0, "ThreadGroupCountZ must no be zero."); + +#undef CHECK_DISPATCH_COMPUTE_ATTRIBS + + return true; +} + +bool VerifyDispatchComputeIndirectAttribs(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) +{ +#define CHECK_DISPATCH_COMPUTE_INDIRECT_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Dispatch compute indirect attribs are invalid: ", __VA_ARGS__) + + CHECK_DISPATCH_COMPUTE_INDIRECT_ATTRIBS(pAttribsBuffer != nullptr, "indirect dispatch arguments buffer must not be null."); + CHECK_DISPATCH_COMPUTE_INDIRECT_ATTRIBS((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) != 0, + "indirect dispatch arguments buffer '", + pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); + +#undef CHECK_DISPATCH_COMPUTE_INDIRECT_ATTRIBS + + return true; +} + +bool VerifyResolveTextureSubresourceAttribs(const ResolveTextureSubresourceAttribs& ResolveAttribs, + const TextureDesc& SrcTexDesc, + const TextureDesc& DstTexDesc) +{ +#define CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Resolve texture subresource attribs are invalid: ", __VA_ARGS__) + + CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(SrcTexDesc.SampleCount > 1, "source texture '", SrcTexDesc.Name, "' of a resolve operation is not multi-sampled"); + CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(DstTexDesc.SampleCount == 1, "destination texture '", DstTexDesc.Name, "' of a resolve operation is multi-sampled"); + + auto SrcMipLevelProps = GetMipLevelProperties(SrcTexDesc, ResolveAttribs.SrcMipLevel); + auto DstMipLevelProps = GetMipLevelProperties(DstTexDesc, ResolveAttribs.DstMipLevel); + CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(SrcMipLevelProps.LogicalWidth == DstMipLevelProps.LogicalWidth && SrcMipLevelProps.LogicalHeight == DstMipLevelProps.LogicalHeight, + "the size (", SrcMipLevelProps.LogicalWidth, "x", SrcMipLevelProps.LogicalHeight, + ") of the source subresource of a resolve operation (texture '", + SrcTexDesc.Name, "', mip ", ResolveAttribs.SrcMipLevel, ", slice ", ResolveAttribs.SrcSlice, + ") does not match the size (", DstMipLevelProps.LogicalWidth, "x", DstMipLevelProps.LogicalHeight, + ") of the destination subresource (texture '", DstTexDesc.Name, "', mip ", ResolveAttribs.DstMipLevel, ", slice ", + ResolveAttribs.DstSlice, ")"); + + const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); + const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format); + const auto& ResolveFmtAttribs = GetTextureFormatAttribs(ResolveAttribs.Format); + if (!SrcFmtAttribs.IsTypeless && !DstFmtAttribs.IsTypeless) + { + CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(SrcTexDesc.Format == DstTexDesc.Format, + "source (", SrcFmtAttribs.Name, ") and destination (", DstFmtAttribs.Name, + ") texture formats of a resolve operation must match exaclty or be compatible typeless formats"); + CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(ResolveAttribs.Format == TEX_FORMAT_UNKNOWN || SrcTexDesc.Format == ResolveAttribs.Format, "Invalid format of a resolve operation"); + } + if (SrcFmtAttribs.IsTypeless && DstFmtAttribs.IsTypeless) + { + CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(ResolveAttribs.Format != TEX_FORMAT_UNKNOWN, + "format of a resolve operation must not be unknown when both src and dst texture formats are typeless"); + } + if (SrcFmtAttribs.IsTypeless || DstFmtAttribs.IsTypeless) + { + CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(!ResolveFmtAttribs.IsTypeless, + "format of a resolve operation must not be typeless when one of the texture formats is typeless"); + } +#undef CHECK_RESOLVE_TEX_SUBRES_ATTRIBS + + return true; +} + +bool VerifyBeginRenderPassAttribs(const BeginRenderPassAttribs& Attribs) +{ +#define CHECK_BEGIN_RENDER_PASS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Begin render pass attribs are invalid: ", __VA_ARGS__) + + CHECK_BEGIN_RENDER_PASS_ATTRIBS(Attribs.pRenderPass != nullptr, "pRenderPass pass must not be null"); + CHECK_BEGIN_RENDER_PASS_ATTRIBS(Attribs.pFramebuffer != nullptr, "pFramebuffer must not be null"); + + const auto& RPDesc = Attribs.pRenderPass->GetDesc(); + + Uint32 NumRequiredClearValues = 0; + for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i) + { + const auto& Attchmnt = RPDesc.pAttachments[i]; + if (Attchmnt.LoadOp == ATTACHMENT_LOAD_OP_CLEAR) + NumRequiredClearValues = i + 1; + + const auto& FmtAttribs = GetTextureFormatAttribs(Attchmnt.Format); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + { + if (Attchmnt.StencilLoadOp == ATTACHMENT_LOAD_OP_CLEAR) + NumRequiredClearValues = i + 1; + } + } + + CHECK_BEGIN_RENDER_PASS_ATTRIBS(Attribs.ClearValueCount >= NumRequiredClearValues, + "at least ", NumRequiredClearValues, " clear values are required, but only ", + Uint32{Attribs.ClearValueCount}, " are provided."); + CHECK_BEGIN_RENDER_PASS_ATTRIBS(Attribs.ClearValueCount == 0 || Attribs.pClearValues != nullptr, + "pClearValues must not be null when ClearValueCount (", Attribs.ClearValueCount, ") is not zero"); + +#undef CHECK_BEGIN_RENDER_PASS_ATTRIBS + + return true; +} + +bool VerifyStateTransitionDesc(const IRenderDevice* pDevice, const StateTransitionDesc& Barrier) +{ +#define CHECK_STATE_TRANSITION_DESC(Expr, ...) CHECK_PARAMETER(Expr, "State transition parameters are invalid: ", __VA_ARGS__) + + CHECK_STATE_TRANSITION_DESC(Barrier.pResource != nullptr, "pResource must not be null"); + CHECK_STATE_TRANSITION_DESC(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "NewState state can't be UNKNOWN"); + + RESOURCE_STATE OldState = RESOURCE_STATE_UNKNOWN; + + if (RefCntAutoPtr<ITexture> pTexture{Barrier.pResource, IID_Texture}) + { + const auto& TexDesc = pTexture->GetDesc(); + + CHECK_STATE_TRANSITION_DESC(VerifyResourceStates(Barrier.NewState, true), "invlaid new state specified for texture '", TexDesc.Name, "'"); + OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pTexture->GetState(); + CHECK_STATE_TRANSITION_DESC(OldState != RESOURCE_STATE_UNKNOWN, + "the state of texture '", TexDesc.Name, + "' is unknown to the engine and is not explicitly specified in the barrier"); + CHECK_STATE_TRANSITION_DESC(VerifyResourceStates(OldState, true), "invlaid old state specified for texture '", TexDesc.Name, "'"); + + CHECK_STATE_TRANSITION_DESC(Barrier.FirstMipLevel < TexDesc.MipLevels, "first mip level (", Barrier.FirstMipLevel, + ") specified by the barrier is out of range. Texture '", + TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)"); + CHECK_STATE_TRANSITION_DESC(Barrier.MipLevelsCount == REMAINING_MIP_LEVELS || Barrier.FirstMipLevel + Barrier.MipLevelsCount <= TexDesc.MipLevels, + "mip level range ", Barrier.FirstMipLevel, "..", Barrier.FirstMipLevel + Barrier.MipLevelsCount - 1, + " specified by the barrier is out of range. Texture '", + TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)"); + + CHECK_STATE_TRANSITION_DESC(Barrier.FirstArraySlice < TexDesc.ArraySize, "first array slice (", Barrier.FirstArraySlice, + ") specified by the barrier is out of range. Array size of texture '", + TexDesc.Name, "' is ", TexDesc.ArraySize); + CHECK_STATE_TRANSITION_DESC(Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES || Barrier.FirstArraySlice + Barrier.ArraySliceCount <= TexDesc.ArraySize, + "array slice range ", Barrier.FirstArraySlice, "..", Barrier.FirstArraySlice + Barrier.ArraySliceCount - 1, + " specified by the barrier is out of range. Array size of texture '", + TexDesc.Name, "' is ", TexDesc.ArraySize); + + auto DevType = pDevice->GetDeviceCaps().DevType; + if (DevType != RENDER_DEVICE_TYPE_D3D12 && DevType != RENDER_DEVICE_TYPE_VULKAN) + { + CHECK_STATE_TRANSITION_DESC(Barrier.FirstMipLevel == 0 && (Barrier.MipLevelsCount == REMAINING_MIP_LEVELS || Barrier.MipLevelsCount == TexDesc.MipLevels), + "failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device"); + CHECK_STATE_TRANSITION_DESC(Barrier.FirstArraySlice == 0 && (Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES || Barrier.ArraySliceCount == TexDesc.ArraySize), + "failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device"); + } + } + else if (RefCntAutoPtr<IBuffer> pBuffer{Barrier.pResource, IID_Buffer}) + { + const auto& BuffDesc = pBuffer->GetDesc(); + CHECK_STATE_TRANSITION_DESC(VerifyResourceStates(Barrier.NewState, false), "invlaid new state specified for buffer '", BuffDesc.Name, "'"); + OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pBuffer->GetState(); + CHECK_STATE_TRANSITION_DESC(OldState != RESOURCE_STATE_UNKNOWN, "the state of buffer '", BuffDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); + CHECK_STATE_TRANSITION_DESC(VerifyResourceStates(OldState, false), "invlaid old state specified for buffer '", BuffDesc.Name, "'"); + } + else if (RefCntAutoPtr<IBottomLevelAS> pBottomLevelAS{Barrier.pResource, IID_BottomLevelAS}) + { + const auto& BLASDesc = pBottomLevelAS->GetDesc(); + OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pBottomLevelAS->GetState(); + CHECK_STATE_TRANSITION_DESC(OldState != RESOURCE_STATE_UNKNOWN, "the state of BLAS '", BLASDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); + CHECK_STATE_TRANSITION_DESC(Barrier.NewState == RESOURCE_STATE_BUILD_AS_READ || Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE, + "invlaid new state specified for BLAS '", BLASDesc.Name, "'"); + CHECK_STATE_TRANSITION_DESC(Barrier.TransitionType != STATE_TRANSITION_TYPE_IMMEDIATE, "split barriers are not supported for BLAS"); + } + else if (RefCntAutoPtr<ITopLevelAS> pTopLevelAS{Barrier.pResource, IID_TopLevelAS}) + { + const auto& TLASDesc = pTopLevelAS->GetDesc(); + OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pTopLevelAS->GetState(); + CHECK_STATE_TRANSITION_DESC(OldState != RESOURCE_STATE_UNKNOWN, "the state of TLAS '", TLASDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); + CHECK_STATE_TRANSITION_DESC(Barrier.NewState == RESOURCE_STATE_BUILD_AS_READ || Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE || Barrier.NewState == RESOURCE_STATE_RAY_TRACING, + "invlaid new state specified for TLAS '", TLASDesc.Name, "'"); + CHECK_STATE_TRANSITION_DESC(Barrier.TransitionType != STATE_TRANSITION_TYPE_IMMEDIATE, "split barriers are not supported for TLAS"); + } + else + { + UNEXPECTED("unsupported resource type"); + } + + if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS) + { + CHECK_STATE_TRANSITION_DESC(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE, "for UAV barriers, transition type must be STATE_TRANSITION_TYPE_IMMEDIATE"); + } + + if (Barrier.TransitionType == STATE_TRANSITION_TYPE_BEGIN) + { + CHECK_STATE_TRANSITION_DESC(!Barrier.UpdateResourceState, "resource state can't be updated in begin-split barrier"); + } + +#undef CHECK_STATE_TRANSITION_DESC + + return true; +} + + +bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs) +{ +#define CHECK_BUILD_BLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Build BLAS attribs are invalid: ", __VA_ARGS__) + + CHECK_BUILD_BLAS_ATTRIBS(Attribs.pBLAS != nullptr, "pBLAS must not be null"); + CHECK_BUILD_BLAS_ATTRIBS(Attribs.pScratchBuffer != nullptr, "pScratchBuffer must not be null"); + CHECK_BUILD_BLAS_ATTRIBS((Attribs.pTriangleData != nullptr) ^ (Attribs.pBoxData != nullptr), "exactly one of pTriangles and pBoxes must be defined"); + CHECK_BUILD_BLAS_ATTRIBS(Attribs.pBoxData != nullptr || Attribs.BoxDataCount == 0, "pBoxData is null, but BoxDataCount is not 0"); + CHECK_BUILD_BLAS_ATTRIBS(Attribs.pTriangleData != nullptr || Attribs.TriangleDataCount == 0, "pTriangleData is null, but TriangleDataCount is not 0"); + + const auto& BLASDesc = Attribs.pBLAS->GetDesc(); + + CHECK_BUILD_BLAS_ATTRIBS(Attribs.BoxDataCount <= BLASDesc.BoxCount, "BoxDataCount must be less than or equal to pBLAS->GetDesc().BoxCount"); + CHECK_BUILD_BLAS_ATTRIBS(Attribs.TriangleDataCount <= BLASDesc.TriangleCount, "TriangleDataCount must be less than or equal to pBLAS->GetDesc().TriangleCount"); + + for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i) + { + const auto& tri = Attribs.pTriangleData[i]; + const Uint32 VertexSize = GetValueSize(tri.VertexValueType) * tri.VertexComponentCount; + const Uint32 VertexDataSize = tri.VertexStride * tri.VertexCount; + const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryIndex(tri.GeometryName); + + CHECK_BUILD_BLAS_ATTRIBS(GeomIndex != InvalidGeometryIndex, + "pTriangleData[", i, "].GeometryName (", tri.GeometryName, ") is not found in BLAS description"); + + const auto& TriDesc = BLASDesc.pTriangles[GeomIndex]; + + CHECK_BUILD_BLAS_ATTRIBS(tri.VertexValueType == VT_UNDEFINED || tri.VertexValueType == TriDesc.VertexValueType, + "pTriangleData[", i, "].VertexValueType must be undefined or match the VertexValueType in geometry description"); + + CHECK_BUILD_BLAS_ATTRIBS(tri.VertexComponentCount == 0 || tri.VertexComponentCount == TriDesc.VertexComponentCount, + "pTriangleData[", i, "].VertexComponentCount (", tri.VertexComponentCount, ") must be 0 or match the VertexComponentCount (", + TriDesc.VertexComponentCount, ") in geometry description"); + + CHECK_BUILD_BLAS_ATTRIBS(tri.VertexCount <= TriDesc.MaxVertexCount, + "pTriangleData[", i, "].VertexCount (", tri.VertexCount, ") must not be greater than MaxVertexCount(", TriDesc.MaxVertexCount, ")"); + + CHECK_BUILD_BLAS_ATTRIBS(tri.VertexStride >= VertexSize, + "pTriangleData[", i, "].VertexStride (", tri.VertexStride, ") must be at least ", VertexSize, " bytes"); + + CHECK_BUILD_BLAS_ATTRIBS(tri.pVertexBuffer != nullptr, "pTriangleData[", i, "].pVertexBuffer must not be null"); + + CHECK_BUILD_BLAS_ATTRIBS((tri.pVertexBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, + "pTriangleData[", i, "].pVertexBuffer was not created with BIND_RAY_TRACING flag"); + + CHECK_BUILD_BLAS_ATTRIBS(tri.VertexOffset + VertexDataSize <= tri.pVertexBuffer->GetDesc().uiSizeInBytes, + "pTriangleData[", i, "].pVertexBuffer is too small for the specified VertexStride (", tri.VertexStride, ") and VertexCount (", + tri.VertexCount, "): at least ", tri.VertexOffset + VertexDataSize, " bytes are required"); + + CHECK_BUILD_BLAS_ATTRIBS(tri.IndexType == VT_UNDEFINED || tri.IndexType == TriDesc.IndexType, + "pTriangleData[", i, "].IndexType (", GetValueTypeString(tri.IndexType), ") must match the IndexType (", + TriDesc.IndexType, ") in geometry description"); + + CHECK_BUILD_BLAS_ATTRIBS(tri.PrimitiveCount <= TriDesc.MaxPrimitiveCount, + "pTriangleData[", i, "].PrimitiveCount (", tri.PrimitiveCount, ") must not be greater than MaxPrimitiveCount (", + TriDesc.MaxPrimitiveCount, ")"); + + if (TriDesc.IndexType != VT_UNDEFINED) + { + CHECK_BUILD_BLAS_ATTRIBS(tri.pIndexBuffer != nullptr, "pTriangleData[", i, "].pIndexBuffer must not be null"); + + CHECK_BUILD_BLAS_ATTRIBS((tri.pIndexBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, + "pTriangleData[", i, "].pIndexBuffer was not created with BIND_RAY_TRACING flag"); + + const Uint32 IndexDataSize = tri.PrimitiveCount * 3 * GetValueSize(tri.IndexType); + CHECK_BUILD_BLAS_ATTRIBS(tri.IndexOffset + IndexDataSize <= tri.pIndexBuffer->GetDesc().uiSizeInBytes, + "pTriangleData[", i, "].pIndexBuffer is too small for specified IndexType and IndexCount: at least", + tri.IndexOffset + IndexDataSize, " bytes are required"); + } + else + { + CHECK_BUILD_BLAS_ATTRIBS(tri.VertexCount == tri.PrimitiveCount * 3, + "pTriangleData[", i, "].VertexCount (", tri.VertexCount, ") must equal to PrimitiveCount * 3 (", + tri.PrimitiveCount * 3, ")"); + + CHECK_BUILD_BLAS_ATTRIBS(tri.pIndexBuffer == nullptr, "pTriangleData[", i, "].pIndexBuffer must be null if IndexType is VT_UNDEFINED"); + } + + if (tri.pTransformBuffer != nullptr) + { + CHECK_BUILD_BLAS_ATTRIBS((tri.pTransformBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, + "pTriangleData[", i, "].pTransformBuffer was not created with BIND_RAY_TRACING flag"); + + CHECK_BUILD_BLAS_ATTRIBS(TriDesc.AllowsTransforms, "pTriangleData[", i, "] uses transform buffer, but AllowsTransforms is false"); + } + } + + for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i) + { + const auto& box = Attribs.pBoxData[i]; + const Uint32 BoxSize = sizeof(float) * 6; + const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryIndex(box.GeometryName); + + CHECK_BUILD_BLAS_ATTRIBS(GeomIndex != InvalidGeometryIndex, + "pBoxData[", i, "].GeometryName (", box.GeometryName, ") is not found in BLAS description"); + + const auto& BoxDesc = BLASDesc.pBoxes[GeomIndex]; + + CHECK_BUILD_BLAS_ATTRIBS(box.BoxCount <= BoxDesc.MaxBoxCount, + "pBoxData[", i, "].BoxCount (", box.BoxCount, ") must not be greated than MaxBoxCount (", BoxDesc.MaxBoxCount, ")"); + + CHECK_BUILD_BLAS_ATTRIBS(box.BoxStride >= BoxSize, + "pBoxData[", i, "].BoxStride (", box.BoxStride, ") must be at least ", BoxSize, " bytes"); + + CHECK_BUILD_BLAS_ATTRIBS(box.pBoxBuffer != nullptr, "pBoxData[", i, "].pBoxBuffer must not be null"); + + CHECK_BUILD_BLAS_ATTRIBS((box.pBoxBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, + "pBoxData[", i, "].pBoxBuffer was not created with BIND_RAY_TRACING flag"); + } + + const auto& ScratchDesc = Attribs.pScratchBuffer->GetDesc(); + + CHECK_BUILD_BLAS_ATTRIBS(Attribs.ScratchBufferOffset <= ScratchDesc.uiSizeInBytes, + "ScratchBufferOffset (", Attribs.ScratchBufferOffset, ") is greater than the buffer size (", ScratchDesc.uiSizeInBytes, ")"); + + CHECK_BUILD_BLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pBLAS->GetScratchBufferSizes().Build, + "pScratchBuffer size is too small, use pBLAS->GetScratchBufferSizes().Build to get the required size for the scratch buffer"); + + CHECK_BUILD_BLAS_ATTRIBS((ScratchDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, + "pScratchBuffer was not created with BIND_RAY_TRACING flag"); + +#undef CHECK_BUILD_BLAS_ATTRIBS + + return true; +} + + +bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs) +{ +#define CHECK_BUILD_TLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Build TLAS attribs are invalid: ", __VA_ARGS__) + + CHECK_BUILD_TLAS_ATTRIBS(Attribs.pTLAS != nullptr, "pTLAS must not be null"); + CHECK_BUILD_TLAS_ATTRIBS(Attribs.pScratchBuffer != nullptr, "pScratchBuffer must not be null"); + CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstances != nullptr, "pInstances must not be null"); + CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstanceBuffer != nullptr, "pInstanceBuffer must not be null"); + CHECK_BUILD_TLAS_ATTRIBS(Attribs.HitShadersPerInstance != 0, "HitShadersPerInstance must be greater than 0"); + + const auto& TLASDesc = Attribs.pTLAS->GetDesc(); + + CHECK_BUILD_TLAS_ATTRIBS(Attribs.InstanceCount <= TLASDesc.MaxInstanceCount, + "InstanceCount (", Attribs.InstanceCount, ") must be less than or equal to pTLAS->GetDesc().MaxInstanceCount (", + TLASDesc.MaxInstanceCount, ")"); + + const auto& InstDesc = Attribs.pInstanceBuffer->GetDesc(); + const auto InstDataSize = size_t{Attribs.InstanceCount} * size_t{TLAS_INSTANCE_DATA_SIZE}; + + Uint32 AutoOffsetCounter = 0; + + // Calculate instance data size + for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) + { + VERIFY((Attribs.pInstances[i].CustomId & ~0x00FFFFFF) == 0, "Only the lower 24 bits are used"); + + VERIFY(Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO || + (Attribs.pInstances[i].ContributionToHitGroupIndex & ~0x00FFFFFF) == 0, + "Only the lower 24 bits are used"); + + CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstances[i].InstanceName != nullptr, "pInstances[", i, "].InstanceName must not be null"); + CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstances[i].pBLAS != nullptr, "pInstances[", i, "].pBLAS must not be null"); + + if (Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO) + ++AutoOffsetCounter; + + CHECK_BUILD_TLAS_ATTRIBS(TLASDesc.BindingMode == SHADER_BINDING_USER_DEFINED || Attribs.pInstances[i].ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO, + "pInstances[", i, + "].ContributionToHitGroupIndex must be TLAS_INSTANCE_OFFSET_AUTO " + "if TLAS is created with BindingMode that is not SHADER_BINDING_USER_DEFINED"); + } + + CHECK_BUILD_TLAS_ATTRIBS(AutoOffsetCounter == 0 || AutoOffsetCounter == Attribs.InstanceCount, + "all pInstances[i].ContributionToHitGroupIndex must be TLAS_INSTANCE_OFFSET_AUTO, or none of them should"); + + CHECK_BUILD_TLAS_ATTRIBS(Attribs.InstanceBufferOffset <= InstDesc.uiSizeInBytes, + "InstanceBufferOffset (", Attribs.InstanceBufferOffset, ") is greater than the buffer size (", InstDesc.uiSizeInBytes, ")"); + + CHECK_BUILD_TLAS_ATTRIBS(InstDesc.uiSizeInBytes - Attribs.InstanceBufferOffset >= InstDataSize, + "pInstanceBuffer size (", InstDesc.uiSizeInBytes, ") is too small: at least ", + InstDataSize + Attribs.InstanceBufferOffset, " bytes are required"); + + CHECK_BUILD_TLAS_ATTRIBS((InstDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, + "pInstanceBuffer was not created with BIND_RAY_TRACING flag"); + + const auto& ScratchDesc = Attribs.pScratchBuffer->GetDesc(); + + CHECK_BUILD_TLAS_ATTRIBS(Attribs.ScratchBufferOffset <= ScratchDesc.uiSizeInBytes, + "ScratchBufferOffset (", Attribs.ScratchBufferOffset, ") is greater than the buffer size (", ScratchDesc.uiSizeInBytes, ")"); + + CHECK_BUILD_TLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pTLAS->GetScratchBufferSizes().Build, + "pScratchBuffer size is too small, use pTLAS->GetScratchBufferSizes().Build to get the required size for scratch buffer"); + + CHECK_BUILD_TLAS_ATTRIBS((ScratchDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING, + "pScratchBuffer was not created with BIND_RAY_TRACING flag"); +#undef CHECK_BUILD_TLAS_ATTRIBS + + return true; +} + + +bool VerifyCopyBLASAttribs(const CopyBLASAttribs& Attribs) +{ +#define CHECK_COPY_BLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Copy BLAS attribs are invalid: ", __VA_ARGS__) + + CHECK_COPY_BLAS_ATTRIBS(Attribs.pSrc != nullptr, "pSrc must not be null"); + CHECK_COPY_BLAS_ATTRIBS(Attribs.pDst != nullptr, "pDst must not be null"); + + if (Attribs.Mode == COPY_AS_MODE_CLONE) + { + auto& SrcDesc = Attribs.pSrc->GetDesc(); + auto& DstDesc = Attribs.pDst->GetDesc(); + + CHECK_COPY_BLAS_ATTRIBS(SrcDesc.TriangleCount == DstDesc.TriangleCount, + "Src BLAS triangle count (", SrcDesc.TriangleCount, ") must be equal to the dst BLAS triangle count (", DstDesc.TriangleCount, ")"); + + CHECK_COPY_BLAS_ATTRIBS(SrcDesc.BoxCount == DstDesc.BoxCount, + "Src BLAS box count (", SrcDesc.BoxCount, ") must be equal to the dst BLAS box count (", DstDesc.BoxCount, ")"); + + CHECK_COPY_BLAS_ATTRIBS(SrcDesc.Flags == DstDesc.Flags, + "Source and destination BLASes must have been created with the same flags"); + + for (Uint32 i = 0; i < SrcDesc.TriangleCount; ++i) + { + auto& SrcTri = SrcDesc.pTriangles[i]; + auto& DstTri = DstDesc.pTriangles[i]; + + CHECK_COPY_BLAS_ATTRIBS(SrcTri.MaxVertexCount == DstTri.MaxVertexCount, + "MaxVertexCount value (", SrcTri.MaxVertexCount, ") in source triangle description at index ", i, + " does not match MaxVertexCount value (", DstTri.MaxVertexCount, ") in the destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.VertexValueType == DstTri.VertexValueType, + "VertexValueType value (", GetValueTypeString(SrcTri.VertexValueType), ") in source triangle description at index ", i, + " does not match VertexValueType value (", GetValueTypeString(DstTri.VertexValueType), ") in destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.VertexComponentCount == DstTri.VertexComponentCount, + "VertexComponentCount value (", Uint32{SrcTri.VertexComponentCount}, ") in source triangle description at index ", i, + " does not match VertexComponentCount value (", Uint32{DstTri.VertexComponentCount}, ") in destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.MaxPrimitiveCount == DstTri.MaxPrimitiveCount, + "MaxPrimitiveCount value (", SrcTri.MaxPrimitiveCount, ") in source triangle description at index ", i, + " does not match MaxPrimitiveCount value (", DstTri.MaxPrimitiveCount, ") in destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.IndexType == DstTri.IndexType, + "IndexType value (", GetValueTypeString(SrcTri.IndexType), ") in source triangle description at index ", i, + " does not match IndexType value (", GetValueTypeString(DstTri.IndexType), ") in destination description"); + CHECK_COPY_BLAS_ATTRIBS(SrcTri.AllowsTransforms == DstTri.AllowsTransforms, + "AllowsTransforms value (", (SrcTri.AllowsTransforms ? "true" : "false"), ") in source triangle description at index ", i, + " does not match AllowsTransforms value (", (DstTri.AllowsTransforms ? "true" : "false"), ") in destination description"); + } + + for (Uint32 i = 0; i < SrcDesc.BoxCount; ++i) + { + CHECK_COPY_BLAS_ATTRIBS(SrcDesc.pBoxes[i].MaxBoxCount == DstDesc.pBoxes[i].MaxBoxCount, + "MaxBoxCountt value (", SrcDesc.pBoxes[i].MaxBoxCount, ") in source box description at index ", i, + " does not match MaxBoxCount value (", DstDesc.pBoxes[i].MaxBoxCount, ") in destination description"); + } + } + else if (Attribs.Mode == COPY_AS_MODE_COMPACT) + { + auto& SrcDesc = Attribs.pSrc->GetDesc(); + auto& DstDesc = Attribs.pDst->GetDesc(); + + CHECK_COPY_BLAS_ATTRIBS((SrcDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION) == RAYTRACING_BUILD_AS_ALLOW_COMPACTION, "must be have been create with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); + CHECK_COPY_BLAS_ATTRIBS(DstDesc.CompactedSize != 0, "pDst must have been create with non-zero CompactedSize"); + } + else + { + LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: unknown Mode"); + return false; + } + +#undef CHECK_COPY_BLAS_ATTRIBS + + return true; +} + + +bool VerifyCopyTLASAttribs(const CopyTLASAttribs& Attribs) +{ +#define CHECK_COPY_TLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Copy TLAS attribs are invalid: ", __VA_ARGS__) + + CHECK_COPY_TLAS_ATTRIBS(Attribs.pSrc != nullptr, "pSrc must not be null"); + CHECK_COPY_TLAS_ATTRIBS(Attribs.pDst != nullptr, "pDst must not be null"); + + if (Attribs.Mode == COPY_AS_MODE_CLONE) + { + auto& SrcDesc = Attribs.pSrc->GetDesc(); + auto& DstDesc = Attribs.pDst->GetDesc(); + + CHECK_COPY_TLAS_ATTRIBS(SrcDesc.MaxInstanceCount == DstDesc.MaxInstanceCount || SrcDesc.Flags == DstDesc.Flags, + "pDst must have been created with the same parameters as pSrc"); + } + else if (Attribs.Mode == COPY_AS_MODE_COMPACT) + { + auto& SrcDesc = Attribs.pSrc->GetDesc(); + auto& DstDesc = Attribs.pDst->GetDesc(); + + CHECK_COPY_TLAS_ATTRIBS((SrcDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION) == RAYTRACING_BUILD_AS_ALLOW_COMPACTION, "pSrc was not created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); + CHECK_COPY_TLAS_ATTRIBS(DstDesc.CompactedSize != 0, "pDst must have been create with non-zero CompactedSize"); + } + else + { + LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: unknown Mode"); + return false; + } +#undef CHECK_COPY_TLAS_ATTRIBS + + return true; +} + +bool VerifyWriteBLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteBLASCompactedSizeAttribs& Attribs) +{ +#define CHECK_WRITE_BLAS_SIZE_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Write compacted BLAS size attribs are invalid: ", __VA_ARGS__) + + CHECK_WRITE_BLAS_SIZE_ATTRIBS(Attribs.pBLAS != nullptr, "pBLAS must not be null"); + CHECK_WRITE_BLAS_SIZE_ATTRIBS((Attribs.pBLAS->GetDesc().Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION) == RAYTRACING_BUILD_AS_ALLOW_COMPACTION, + "pBLAS was not created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); + + CHECK_WRITE_BLAS_SIZE_ATTRIBS(Attribs.pDestBuffer != nullptr, "pDestBuffer must not be null"); + CHECK_WRITE_BLAS_SIZE_ATTRIBS(Attribs.DestBufferOffset + sizeof(Uint64) <= Attribs.pDestBuffer->GetDesc().uiSizeInBytes, + "pDestBuffer is too small"); + + if (pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_D3D12) + { + CHECK_WRITE_BLAS_SIZE_ATTRIBS((Attribs.pDestBuffer->GetDesc().BindFlags & BIND_UNORDERED_ACCESS) == BIND_UNORDERED_ACCESS, + "pDestBuffer must have been created with BIND_UNORDERED_ACCESS flag in Direct3D12"); + } + +#undef CHECK_WRITE_BLAS_SIZE_ATTRIBS + + return true; +} + +bool VerifyWriteTLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteTLASCompactedSizeAttribs& Attribs) +{ +#define CHECK_WRITE_TLAS_SIZE_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Write compacted TLAS size attribs are invalid: ", __VA_ARGS__) + + CHECK_WRITE_TLAS_SIZE_ATTRIBS(Attribs.pTLAS != nullptr, "pTLAS must not be null"); + CHECK_WRITE_TLAS_SIZE_ATTRIBS((Attribs.pTLAS->GetDesc().Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION) == RAYTRACING_BUILD_AS_ALLOW_COMPACTION, + "pTLAS was not created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag"); + + CHECK_WRITE_TLAS_SIZE_ATTRIBS(Attribs.pDestBuffer != nullptr, "pDestBuffer must not be null"); + CHECK_WRITE_TLAS_SIZE_ATTRIBS(Attribs.DestBufferOffset + sizeof(Uint64) <= Attribs.pDestBuffer->GetDesc().uiSizeInBytes, "pDestBuffer is too small"); + + if (pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_D3D12) + { + CHECK_WRITE_TLAS_SIZE_ATTRIBS((Attribs.pDestBuffer->GetDesc().BindFlags & BIND_UNORDERED_ACCESS) == BIND_UNORDERED_ACCESS, + "pDestBuffer must have been created with BIND_UNORDERED_ACCESS flag"); + } + +#undef CHECK_WRITE_TLAS_SIZE_ATTRIBS + + return true; +} + +bool VerifyTraceRaysAttribs(const TraceRaysAttribs& Attribs) +{ +#define CHECK_TRACE_RAYS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Trace rays attribs are invalid: ", __VA_ARGS__) + CHECK_TRACE_RAYS_ATTRIBS(Attribs.pSBT != nullptr, "pSBT must not be null"); + +#ifdef DILIGENT_DEVELOPMENT + CHECK_TRACE_RAYS_ATTRIBS(Attribs.pSBT->Verify(), "pSBT content is not valid"); +#endif // DILIGENT_DEVELOPMENT + + CHECK_TRACE_RAYS_ATTRIBS(Attribs.DimensionX != 0, "DimensionX must not be zero."); + CHECK_TRACE_RAYS_ATTRIBS(Attribs.DimensionY != 0, "DimensionY must not be zero."); + CHECK_TRACE_RAYS_ATTRIBS(Attribs.DimensionZ != 0, "DimensionZ must not be zero."); + +#undef CHECK_TRACE_RAYS_ATTRIBS + + return true; +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngine/src/FramebufferBase.cpp b/Graphics/GraphicsEngine/src/FramebufferBase.cpp index 0434bf0a..1a173910 100644 --- a/Graphics/GraphicsEngine/src/FramebufferBase.cpp +++ b/Graphics/GraphicsEngine/src/FramebufferBase.cpp @@ -31,7 +31,7 @@ namespace Diligent { -void ValidateFramebufferDesc(const FramebufferDesc& Desc) +void ValidateFramebufferDesc(const FramebufferDesc& Desc) noexcept(false) { #define LOG_FRAMEBUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of framebuffer '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__) |
