From 5ea80a116bc5ff82d8ef10243f7fba103a4d0961 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Mon, 19 Nov 2018 21:26:49 -0800 Subject: Implemented explicit layout transitions in Vulkan backend --- .../GraphicsEngineVulkan/include/BufferVkImpl.h | 15 +- .../include/DeviceContextVkImpl.h | 43 ++- .../GraphicsEngineVulkan/include/TextureVkImpl.h | 10 +- .../include/VulkanTypeConversions.h | 3 + .../interface/DeviceContextVk.h | 2 + .../GraphicsEngineVulkan/interface/TextureVk.h | 11 +- Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp | 53 +++- .../src/DeviceContextVkImpl.cpp | 348 +++++++++++++++++---- .../src/GenerateMipsVkHelper.cpp | 20 +- .../src/ShaderResourceCacheVk.cpp | 137 ++++---- .../GraphicsEngineVulkan/src/TextureVkImpl.cpp | 27 +- .../src/VulkanTypeConversions.cpp | 110 ++++++- 12 files changed, 600 insertions(+), 179 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h index da856b3c..9e888bec 100644 --- a/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h @@ -99,17 +99,11 @@ public: return vkBuffer; } - virtual void SetAccessFlags(VkAccessFlags AccessFlags)override final + virtual void SetAccessFlags(VkAccessFlags AccessFlags)override final; + VkAccessFlags GetAccessFlags()const; + bool CheckAccessFlags(VkAccessFlags AccessFlags)const { - m_AccessFlags = AccessFlags; - } - bool CheckAccessFlags(VkAccessFlags Flags)const - { - return (m_AccessFlags & Flags) == Flags; - } - VkAccessFlags GetAccessFlags()const - { - return m_AccessFlags; + return (GetAccessFlags() & AccessFlags) == AccessFlags; } private: @@ -118,7 +112,6 @@ private: virtual void CreateViewInternal( const struct BufferViewDesc& ViewDesc, IBufferView** ppView, bool bIsDefaultView )override; VulkanUtilities::BufferViewWrapper CreateView(struct BufferViewDesc &ViewDesc); - VkAccessFlags m_AccessFlags = 0; Uint32 m_DynamicOffsetAlignment = 0; #ifdef DEVELOPMENT diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h index 9ba4ca8f..e75c7deb 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h @@ -87,27 +87,48 @@ public: virtual void Draw( DrawAttribs &DrawAttribs )override final; - virtual void DispatchCompute( const DispatchComputeAttribs &DispatchAttrs )override final; + virtual void DispatchCompute( const DispatchComputeAttribs& DispatchAttrs )override final; virtual void ClearDepthStencil( ITextureView* pView, Uint32 ClearFlags, float fDepth, Uint8 Stencil)override final; - virtual void ClearRenderTarget( ITextureView* pView, const float *RGBA )override final; + virtual void ClearRenderTarget( ITextureView* pView, const float* RGBA )override final; virtual void Flush()override final; - virtual void FinishCommandList(class ICommandList **ppCommandList)override final; + virtual void FinishCommandList(class ICommandList** ppCommandList)override final; virtual void ExecuteCommandList(class ICommandList* pCommandList)override final; virtual void SignalFence(IFence* pFence, Uint64 Value)override final; - void TransitionImageLayout(class TextureVkImpl &TextureVk, VkImageLayout NewLayout); - void TransitionImageLayout(class TextureVkImpl &TextureVk, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange); + // Transitions texture subresources from OldState to NewState, and optionally updates + // internal texture state. + // If OldState == RESOURCE_STATE_UNKNOWN, internal texture state is used as old state. + void TransitionTextureState(TextureVkImpl& TextureVk, + RESOURCE_STATE OldState, + RESOURCE_STATE NewState, + bool UpdateTextureState, + VkImageSubresourceRange* pSubresRange = nullptr); + + void TransitionImageLayout(TextureVkImpl& TextureVk, + VkImageLayout OldLayout, + VkImageLayout NewLayout, + const VkImageSubresourceRange& SubresRange); + virtual void TransitionImageLayout(ITexture* pTexture, VkImageLayout NewLayout)override final; - void BufferMemoryBarrier(class BufferVkImpl &BufferVk, VkAccessFlags NewAccessFlags); + + // Transitions buffer state from OldState to NewState, and optionally updates + // internal buffer state. + // If OldState == RESOURCE_STATE_UNKNOWN, internal buffer state is used as old state. + void TransitionBufferState(BufferVkImpl& BufferVk, + RESOURCE_STATE OldState, + RESOURCE_STATE NewState, + bool UpdateBufferState); + virtual void BufferMemoryBarrier(IBuffer* pBuffer, VkAccessFlags NewAccessFlags)override final; + void AddWaitSemaphore(VkSemaphore Semaphore, VkPipelineStageFlags WaitDstStageMask) { m_WaitSemaphores.push_back(Semaphore); @@ -118,16 +139,16 @@ public: m_SignalSemaphores.push_back(Semaphore); } - void UpdateBufferRegion(class BufferVkImpl* pBuffVk, Uint64 DstOffset, Uint64 NumBytes, VkBuffer vkSrcBuffer, Uint64 SrcOffset); - void UpdateBufferRegion(class BufferVkImpl* pBuffVk, const void* pData, Uint64 DstOffset, Uint64 NumBytes); + void UpdateBufferRegion(BufferVkImpl* pBuffVk, Uint64 DstOffset, Uint64 NumBytes, VkBuffer vkSrcBuffer, Uint64 SrcOffset); + void UpdateBufferRegion(BufferVkImpl* pBuffVk, const void* pData, Uint64 DstOffset, Uint64 NumBytes); - void CopyBufferRegion(class BufferVkImpl* pSrcBuffVk, class BufferVkImpl* pDstBuffVk, Uint64 SrcOffset, Uint64 DstOffset, Uint64 NumBytes); - void CopyTextureRegion(class TextureVkImpl* pSrcTexture, class TextureVkImpl* pDstTexture, const VkImageCopy &CopyRegion); + void CopyBufferRegion(BufferVkImpl* pSrcBuffVk, BufferVkImpl* pDstBuffVk, Uint64 SrcOffset, Uint64 DstOffset, Uint64 NumBytes); + void CopyTextureRegion(TextureVkImpl* pSrcTexture, TextureVkImpl* pDstTexture, const VkImageCopy &CopyRegion); void UpdateTextureRegion(const void* pSrcData, Uint32 SrcStride, Uint32 SrcDepthStride, - class TextureVkImpl& TextureVk, + TextureVkImpl& TextureVk, Uint32 MipLevel, Uint32 Slice, const Box& DstBox); diff --git a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h index df416323..eddf48af 100644 --- a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h @@ -81,9 +81,6 @@ public: auto vkImage = GetVkImage(); return vkImage; } -/* - virtual void SetVkResourceState(Vk_RESOURCE_STATES state)override final{ SetState(state); } - */ void CopyData(IDeviceContext* pContext, ITexture* pSrcTexture, @@ -106,11 +103,11 @@ public: return m_MipLevelUAV[MipLevel].get(); } - void SetLayout(VkImageLayout NewLayout){ m_CurrentLayout = NewLayout;} - VkImageLayout GetLayout()const{return m_CurrentLayout;} + + void SetLayout(VkImageLayout Layout)override final; + VkImageLayout GetLayout()const override final; protected: - void CreateViewInternal( const struct TextureViewDesc& ViewDesc, ITextureView** ppView, bool bIsDefaultView )override; //void PrepareVkInitData(const TextureData &InitData, Uint32 NumSubresources, std::vector &VkInitData); @@ -118,7 +115,6 @@ protected: VulkanUtilities::ImageWrapper m_VulkanImage; VulkanUtilities::VulkanMemoryAllocation m_MemoryAllocation; - VkImageLayout m_CurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Texture views needed for mipmap generation std::vector > > m_MipLevelSRV; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h index 49bd0810..b7359a7a 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h @@ -61,4 +61,7 @@ VkBorderColor BorderColorToVkBorderColor(const Float32 BorderColor[]); VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags); VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag); +RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlags AccessFlags); +RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout); + } diff --git a/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h b/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h index cb8eb676..377daaa3 100644 --- a/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h @@ -44,12 +44,14 @@ public: /// \param [in] pTexture - texture to transition /// \param [in] NewLayout - Vulkan image layout this texture to transition to + /// \remarks The texture state must be known to the engine. virtual void TransitionImageLayout(ITexture *pTexture, VkImageLayout NewLayout) = 0; /// Transitions internal vulkan buffer object to a specified state /// \param [in] pBuffer - Buffer to transition /// \param [in] NewAccessFlags - Access flags to set for the buffer + /// \remarks The buffer state must be known to the engine. virtual void BufferMemoryBarrier(IBuffer *pBuffer, VkAccessFlags NewAccessFlags) = 0; }; diff --git a/Graphics/GraphicsEngineVulkan/interface/TextureVk.h b/Graphics/GraphicsEngineVulkan/interface/TextureVk.h index 43aca681..556713ec 100644 --- a/Graphics/GraphicsEngineVulkan/interface/TextureVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/TextureVk.h @@ -46,10 +46,15 @@ public: /// The application must not release the returned image virtual VkImage GetVkImage()const = 0; - /// Sets the texture usage state + /// Sets Vulkan image layout - /// \param [in] state - D3D12 resource state to be set for this texture - //virtual void SetD3D12ResourceState(D3D12_RESOURCE_STATES state) = 0; + /// \param [in] Layout - Vulkan image layout to set. + /// \note This function does not perform layout transition, but sets the + /// internal texture state to match the given Vulkan layout. + virtual void SetLayout(VkImageLayout Layout) = 0; + + /// Returns current Vulkan image layout. If the state is unknown to the engine, returns VK_IMAGE_LAYOUT_UNDEFINED + virtual VkImageLayout GetLayout()const = 0; }; } diff --git a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp index c6ed186f..c31ac7c3 100644 --- a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp @@ -42,7 +42,6 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, const BufferDesc& BuffDesc, const BufferData& BuffData /*= BufferData()*/) : TBufferBase(pRefCounters, BuffViewObjMemAllocator, pRenderDeviceVk, BuffDesc, false), - m_AccessFlags(0), #ifdef DEVELOPMENT m_DvpMapType(1 + pRenderDeviceVk->GetNumDeferredContexts()), #endif @@ -142,12 +141,26 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, { // Dynamic constant/vertex/index buffers are suballocated in the upload heap when Map() is called. // Dynamic buffers with SRV or UAV flags need to be allocated in GPU-only memory - m_AccessFlags = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | - VK_ACCESS_INDEX_READ_BIT | - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - VK_ACCESS_UNIFORM_READ_BIT | - VK_ACCESS_SHADER_READ_BIT | - VK_ACCESS_TRANSFER_READ_BIT; + constexpr RESOURCE_STATE State = static_cast( + RESOURCE_STATE_VERTEX_BUFFER | + RESOURCE_STATE_INDEX_BUFFER | + RESOURCE_STATE_CONSTANT_BUFFER | + RESOURCE_STATE_SHADER_RESOURCE | + RESOURCE_STATE_COPY_SOURCE | + RESOURCE_STATE_INDIRECT_ARGUMENT); + SetState(State); + +#ifdef _DEBUG + { + VkAccessFlags AccessFlags = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_TRANSFER_READ_BIT; + VERIFY_EXPR(ResourceStateFlagsToVkAccessFlags(State) == AccessFlags); + } +#endif } else { @@ -176,6 +189,7 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, CHECK_VK_ERROR_AND_THROW(err, "Failed to bind buffer memory"); bool bInitializeBuffer = (BuffData.pData != nullptr && BuffData.DataSize > 0); + RESOURCE_STATE InitialState = RESOURCE_STATE_UNDEFINED; if( bInitializeBuffer ) { VkBufferCreateInfo VkStaginBuffCI = VkBuffCI; @@ -210,8 +224,10 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, pRenderDeviceVk->AllocateTransientCmdPool(CmdPool, vkCmdBuff, "Transient command pool to copy staging data to a device buffer"); VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT); - m_AccessFlags = VK_ACCESS_TRANSFER_WRITE_BIT; - VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, m_VulkanBuffer, 0, m_AccessFlags); + InitialState = RESOURCE_STATE_COPY_DEST; + VkAccessFlags AccessFlags = ResourceStateFlagsToVkAccessFlags(InitialState); + VERIFY_EXPR(AccessFlags == VK_ACCESS_TRANSFER_WRITE_BIT); + VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, m_VulkanBuffer, 0, AccessFlags); // Copy commands MUST be recorded outside of a render pass instance. This is OK here // as copy will be the only command in the cmd buffer @@ -252,11 +268,11 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, pRenderDeviceVk->SafeReleaseDeviceObject(std::move(StagingBuffer), Uint64{1} << Uint64{QueueIndex}); pRenderDeviceVk->SafeReleaseDeviceObject(std::move(StagingMemoryAllocation), Uint64{1} << Uint64{QueueIndex}); } - else - { - m_AccessFlags = 0; - } + + SetState(InitialState); } + + VERIFY_EXPR(IsInKnownState()); } @@ -267,7 +283,6 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, RESOURCE_STATE InitialState, VkBuffer vkBuffer) : TBufferBase(pRefCounters, BuffViewObjMemAllocator, pRenderDeviceVk, BuffDesc, false), - m_AccessFlags(0), #ifdef DEVELOPMENT m_DvpMapType(1 + pRenderDeviceVk->GetNumDeferredContexts()), #endif @@ -527,6 +542,16 @@ VkBuffer BufferVkImpl::GetVkBuffer()const } } +void BufferVkImpl::SetAccessFlags(VkAccessFlags AccessFlags) +{ + SetState(VkAccessFlagsToResourceStates(AccessFlags)); +} + +VkAccessFlags BufferVkImpl::GetAccessFlags()const +{ + return ResourceStateFlagsToVkAccessFlags(GetState()); +} + #ifdef DEVELOPMENT void BufferVkImpl::DvpVerifyDynamicAllocation(DeviceContextVkImpl* pCtx)const { diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index a08517e4..d9cc8bf6 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -295,8 +295,14 @@ namespace Diligent { auto& CurrStream = m_VertexStreams[Buff]; auto* pBufferVk = CurrStream.pBuffer.RawPtr(); - if (pBufferVk != nullptr && !pBufferVk->CheckAccessFlags(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) - BufferMemoryBarrier(*pBufferVk, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT); + if (pBufferVk != nullptr && pBufferVk->IsInKnownState()) + { + if (!pBufferVk->CheckState(RESOURCE_STATE_VERTEX_BUFFER)) + { + TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_VERTEX_BUFFER, true); + } + VERIFY_EXPR(pBufferVk->CheckAccessFlags(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)); + } } } @@ -323,8 +329,14 @@ namespace Diligent pBufferVk->DvpVerifyDynamicAllocation(this); #endif } - if (!pBufferVk->CheckAccessFlags(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) - BufferMemoryBarrier(*pBufferVk, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT); + if (pBufferVk->IsInKnownState()) + { + if (!pBufferVk->CheckState(RESOURCE_STATE_VERTEX_BUFFER)) + { + TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_VERTEX_BUFFER, true); + } + VERIFY_EXPR(pBufferVk->CheckAccessFlags(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)); + } // Device context keeps strong references to all vertex buffers. @@ -408,8 +420,14 @@ namespace Diligent #endif BufferVkImpl *pBuffVk = m_pIndexBuffer.RawPtr(); - if (!pBuffVk->CheckAccessFlags(VK_ACCESS_INDEX_READ_BIT)) - BufferMemoryBarrier(*pBuffVk, VK_ACCESS_INDEX_READ_BIT); + if (pBuffVk->IsInKnownState()) + { + if (!pBuffVk->CheckState(RESOURCE_STATE_INDEX_BUFFER)) + { + TransitionBufferState(*pBuffVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_INDEX_BUFFER, true); + } + VERIFY_EXPR(pBuffVk->CheckAccessFlags(VK_ACCESS_INDEX_READ_BIT)); + } DEV_CHECK_ERR(drawAttribs.IndexType == VT_UINT16 || drawAttribs.IndexType == VT_UINT32, "Unsupported index format. Only R16_UINT and R32_UINT are allowed."); VkIndexType vkIndexType = drawAttribs.IndexType == VT_UINT16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; @@ -437,8 +455,14 @@ namespace Diligent if (pIndirectDrawAttribsVk != nullptr) { // Buffer memory barries must be executed outside of render pass - if (!pIndirectDrawAttribsVk->CheckAccessFlags(VK_ACCESS_INDIRECT_COMMAND_READ_BIT)) - BufferMemoryBarrier(*pIndirectDrawAttribsVk, VK_ACCESS_INDIRECT_COMMAND_READ_BIT); + if (pIndirectDrawAttribsVk->IsInKnownState()) + { + if (!pIndirectDrawAttribsVk->CheckState(RESOURCE_STATE_INDIRECT_ARGUMENT)) + { + TransitionBufferState(*pIndirectDrawAttribsVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_INDIRECT_ARGUMENT, true); + } + VERIFY_EXPR(pIndirectDrawAttribsVk->CheckAccessFlags(VK_ACCESS_INDIRECT_COMMAND_READ_BIT)); + } } #ifdef DEVELOPMENT @@ -456,8 +480,14 @@ namespace Diligent if (pIndirectDrawAttribsVk->GetDesc().Usage == USAGE_DYNAMIC) pIndirectDrawAttribsVk->DvpVerifyDynamicAllocation(this); #endif - if (!pIndirectDrawAttribsVk->CheckAccessFlags(VK_ACCESS_INDIRECT_COMMAND_READ_BIT)) - BufferMemoryBarrier(*pIndirectDrawAttribsVk, VK_ACCESS_INDIRECT_COMMAND_READ_BIT); + if (pIndirectDrawAttribsVk->IsInKnownState()) + { + if (!pIndirectDrawAttribsVk->CheckState(RESOURCE_STATE_INDIRECT_ARGUMENT)) + { + TransitionBufferState(*pIndirectDrawAttribsVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_INDIRECT_ARGUMENT, true); + } + VERIFY_EXPR(pIndirectDrawAttribsVk->CheckAccessFlags(VK_ACCESS_INDIRECT_COMMAND_READ_BIT)); + } if ( drawAttribs.IsIndexed ) m_CommandBuffer.DrawIndexedIndirect(pIndirectDrawAttribsVk->GetVkBuffer(), pIndirectDrawAttribsVk->GetDynamicOffset(m_ContextId, this) + drawAttribs.IndirectDrawArgsOffset, 1, 0); @@ -510,8 +540,14 @@ namespace Diligent #endif // Buffer memory barries must be executed outside of render pass - if (!pBufferVk->CheckAccessFlags(VK_ACCESS_INDIRECT_COMMAND_READ_BIT)) - BufferMemoryBarrier(*pBufferVk, VK_ACCESS_INDIRECT_COMMAND_READ_BIT); + if (pBufferVk->IsInKnownState()) + { + if (!pBufferVk->CheckState(RESOURCE_STATE_INDIRECT_ARGUMENT)) + { + TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_INDIRECT_ARGUMENT, true); + } + VERIFY_EXPR(pBufferVk->CheckAccessFlags(VK_ACCESS_INDIRECT_COMMAND_READ_BIT)); + } m_CommandBuffer.DispatchIndirect(pBufferVk->GetVkBuffer(), pBufferVk->GetDynamicOffset(m_ContextId, this) + DispatchAttrs.DispatchArgsByteOffset); } @@ -594,7 +630,15 @@ namespace Diligent auto* pTextureVk = ValidatedCast(pTexture); // Image layout must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL (17.1) - TransitionImageLayout(pTexture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + if (pTextureVk->IsInKnownState()) + { + if (!pTextureVk->CheckState(RESOURCE_STATE_COPY_DEST)) + { + TransitionTextureState(*pTextureVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_COPY_DEST, true); + } + VERIFY_EXPR(pTextureVk->GetLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + } + VkClearDepthStencilValue ClearValue; ClearValue.depth = fDepth; ClearValue.stencil = Stencil; @@ -721,7 +765,14 @@ namespace Diligent auto* pTextureVk = ValidatedCast(pTexture); // Image layout must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL (17.1) - TransitionImageLayout(pTexture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + if (pTextureVk->IsInKnownState()) + { + if (!pTextureVk->CheckState(RESOURCE_STATE_COPY_DEST)) + { + TransitionTextureState(*pTextureVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_COPY_DEST, true); + } + VERIFY_EXPR(pTextureVk->GetLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + } auto ClearValue = ClearValueToVkClearValue(RGBA, ViewDesc.Format); VkImageSubresourceRange Subresource; Subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -962,8 +1013,15 @@ namespace Diligent if (m_pBoundDepthStencil) { auto* pDSVVk = m_pBoundDepthStencil.RawPtr(); - auto* pDepthBuffer = pDSVVk->GetTexture(); - TransitionImageLayout(pDepthBuffer, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + auto* pDepthBufferVk = ValidatedCast(pDSVVk->GetTexture()); + if (pDepthBufferVk->IsInKnownState()) + { + if (!pDepthBufferVk->CheckState(RESOURCE_STATE_DEPTH_WRITE)) + { + TransitionTextureState(*pDepthBufferVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_DEPTH_WRITE, true); + } + VERIFY_EXPR(pDepthBufferVk->GetLayout() == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } } for (Uint32 rt=0; rt < m_NumBoundRenderTargets; ++rt) @@ -971,8 +1029,15 @@ namespace Diligent if (ITextureView* pRTV = m_pBoundRenderTargets[rt]) { auto* pRTVVk = ValidatedCast(pRTV); - auto* pRenderTarget = pRTVVk->GetTexture(); - TransitionImageLayout(pRenderTarget, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + auto* pRenderTargetVk = ValidatedCast(pRTVVk->GetTexture()); + if (pRenderTargetVk->IsInKnownState()) + { + if (!pRenderTargetVk->CheckState(RESOURCE_STATE_RENDER_TARGET)) + { + TransitionTextureState(*pRenderTargetVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_RENDER_TARGET, true); + } + VERIFY_EXPR(pRenderTargetVk->GetLayout() == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } } } m_CommandBuffer.BeginRenderPass(m_RenderPass, m_Framebuffer, m_FramebufferWidth, m_FramebufferHeight); @@ -1057,9 +1122,13 @@ namespace Diligent #endif EnsureVkCmdBuffer(); - if (!pBuffVk->CheckAccessFlags(VK_ACCESS_TRANSFER_WRITE_BIT)) + if (pBuffVk->IsInKnownState()) { - BufferMemoryBarrier(*pBuffVk, VK_ACCESS_TRANSFER_WRITE_BIT); + if (!pBuffVk->CheckState(RESOURCE_STATE_COPY_DEST)) + { + TransitionBufferState(*pBuffVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_COPY_DEST, true); + } + VERIFY_EXPR(pBuffVk->CheckAccessFlags(VK_ACCESS_TRANSFER_WRITE_BIT)); } VkBufferCopy CopyRegion; CopyRegion.srcOffset = SrcOffset; @@ -1101,10 +1170,23 @@ namespace Diligent #endif EnsureVkCmdBuffer(); - if (!pSrcBuffVk->CheckAccessFlags(VK_ACCESS_TRANSFER_READ_BIT)) - BufferMemoryBarrier(*pSrcBuffVk, VK_ACCESS_TRANSFER_READ_BIT); - if (!pDstBuffVk->CheckAccessFlags(VK_ACCESS_TRANSFER_WRITE_BIT)) - BufferMemoryBarrier(*pDstBuffVk, VK_ACCESS_TRANSFER_WRITE_BIT); + if (pSrcBuffVk->IsInKnownState()) + { + if (!pSrcBuffVk->CheckState(RESOURCE_STATE_COPY_SOURCE)) + { + TransitionBufferState(*pSrcBuffVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_COPY_SOURCE, true); + } + VERIFY_EXPR(pSrcBuffVk->CheckAccessFlags(VK_ACCESS_TRANSFER_READ_BIT)); + } + if (pDstBuffVk->IsInKnownState()) + { + if (!pDstBuffVk->CheckState(RESOURCE_STATE_COPY_DEST)) + { + TransitionBufferState(*pDstBuffVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_COPY_DEST, true); + } + VERIFY_EXPR(pDstBuffVk->CheckAccessFlags(VK_ACCESS_TRANSFER_WRITE_BIT)); + } + VkBufferCopy CopyRegion; CopyRegion.srcOffset = SrcOffset + pSrcBuffVk->GetDynamicOffset(m_ContextId, this); CopyRegion.dstOffset = DstOffset; @@ -1118,13 +1200,21 @@ namespace Diligent void DeviceContextVkImpl::CopyTextureRegion(TextureVkImpl *pSrcTexture, TextureVkImpl *pDstTexture, const VkImageCopy &CopyRegion) { EnsureVkCmdBuffer(); - if (pSrcTexture->GetLayout() != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) + if (pSrcTexture->IsInKnownState()) { - TransitionImageLayout(*pSrcTexture, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + if (!pSrcTexture->CheckState(RESOURCE_STATE_COPY_SOURCE)) + { + TransitionTextureState(*pSrcTexture, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_COPY_SOURCE, true); + } + VERIFY_EXPR(pSrcTexture->GetLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); } - if (pDstTexture->GetLayout() != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + if (pDstTexture->IsInKnownState()) { - TransitionImageLayout(*pDstTexture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + if (!pDstTexture->CheckState(RESOURCE_STATE_COPY_DEST)) + { + TransitionTextureState(*pDstTexture, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_COPY_DEST, true); + } + VERIFY_EXPR(pDstTexture->GetLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } // srcImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL // dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.3) @@ -1174,7 +1264,7 @@ namespace Diligent CopyInfo.Stride = Align(CopyInfo.RowSize, static_cast(DeviceLimits.optimalBufferCopyRowPitchAlignment)); if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) { - // If the calling command�s VkImage parameter is a compressed image, + // If the calling command's VkImage parameter is a compressed image, // bufferRowLength must be a multiple of the compressed texel block width // In texels (not even in compressed blocks!) CopyInfo.StrideInTexels = CopyInfo.Stride / Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.BlockWidth}; @@ -1260,9 +1350,13 @@ namespace Diligent Uint32 ArraySlice) { EnsureVkCmdBuffer(); - if (TextureVk.GetLayout() != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + if (TextureVk.IsInKnownState()) { - TransitionImageLayout(TextureVk, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + if (!TextureVk.CheckState(RESOURCE_STATE_COPY_DEST)) + { + TransitionTextureState(TextureVk, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_COPY_DEST, true); + } + VERIFY_EXPR(TextureVk.GetLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } VkBufferImageCopy CopyRegion = {}; @@ -1443,45 +1537,92 @@ namespace Diligent m_PendingFences.emplace_back( std::make_pair(Value, pFence) ); }; - void DeviceContextVkImpl::TransitionImageLayout(ITexture *pTexture, VkImageLayout NewLayout) + void DeviceContextVkImpl::TransitionImageLayout(ITexture* pTexture, VkImageLayout NewLayout) { VERIFY_EXPR(pTexture != nullptr); auto pTextureVk = ValidatedCast(pTexture); - if (pTextureVk->GetLayout() != NewLayout) + if (!pTextureVk->IsInKnownState()) { - TransitionImageLayout(*pTextureVk, NewLayout); + LOG_ERROR_MESSAGE("Failed to transition layout for texture '", pTextureVk->GetDesc().Name, "' because the texture state is unknown"); + return; + } + auto NewState = VkImageLayoutToResourceState(NewLayout); + if (!pTextureVk->CheckState(NewState)) + { + TransitionTextureState(*pTextureVk, RESOURCE_STATE_UNKNOWN, NewState, true); } } - void DeviceContextVkImpl::TransitionImageLayout(TextureVkImpl& TextureVk, VkImageLayout NewLayout) + void DeviceContextVkImpl::TransitionTextureState(TextureVkImpl& TextureVk, + RESOURCE_STATE OldState, + RESOURCE_STATE NewState, + bool UpdateTextureState, + VkImageSubresourceRange* pSubresRange/* = nullptr*/) { - VERIFY(TextureVk.GetLayout() != NewLayout, "The texture is already transitioned to correct layout"); + if (OldState == RESOURCE_STATE_UNKNOWN) + { + if (TextureVk.IsInKnownState()) + { + OldState = TextureVk.GetState(); + } + else + { + LOG_ERROR_MESSAGE("Failed to transition the state of texture '", TextureVk.GetDesc().Name, "' because the texture state is unknown and is not explicitly specified"); + return; + } + } + else + { + if (TextureVk.IsInKnownState() && TextureVk.GetState() != OldState) + { + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(TextureVk.GetState()), " of texture '", + TextureVk.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + " specified by the barrier"); + } + } + EnsureVkCmdBuffer(); - + auto vkImg = TextureVk.GetVkImage(); - const auto& TexDesc = TextureVk.GetDesc(); - const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); - VkImageSubresourceRange SubresRange; - if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) - SubresRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + VkImageSubresourceRange FullSubresRange; + if (pSubresRange == nullptr) { - // If image has a depth / stencil format with both depth and stencil components, then the - // aspectMask member of subresourceRange must include both VK_IMAGE_ASPECT_DEPTH_BIT and - // VK_IMAGE_ASPECT_STENCIL_BIT (6.7.3) - SubresRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + pSubresRange = &FullSubresRange; + FullSubresRange.aspectMask = 0; + FullSubresRange.baseArrayLayer = 0; + FullSubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + FullSubresRange.baseMipLevel = 0; + FullSubresRange.levelCount = VK_REMAINING_MIP_LEVELS; + } + + if (pSubresRange->aspectMask == 0) + { + const auto& TexDesc = TextureVk.GetDesc(); + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) + pSubresRange->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + { + // If image has a depth / stencil format with both depth and stencil components, then the + // aspectMask member of subresourceRange must include both VK_IMAGE_ASPECT_DEPTH_BIT and + // VK_IMAGE_ASPECT_STENCIL_BIT (6.7.3) + pSubresRange->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + } + else + pSubresRange->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + auto OldLayout = ResourceStateToVkImageLayout(OldState); + auto NewLayout = ResourceStateToVkImageLayout(NewState); + m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, *pSubresRange); + if(UpdateTextureState) + { + TextureVk.SetState(NewState); + VERIFY_EXPR(TextureVk.GetLayout() == NewLayout); } - else - SubresRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - SubresRange.baseArrayLayer = 0; - SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; - SubresRange.baseMipLevel = 0; - SubresRange.levelCount = VK_REMAINING_MIP_LEVELS; - m_CommandBuffer.TransitionImageLayout(vkImg, TextureVk.GetLayout(), NewLayout, SubresRange); - TextureVk.SetLayout(NewLayout); } - void DeviceContextVkImpl::TransitionImageLayout(TextureVkImpl &TextureVk, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange) + void DeviceContextVkImpl::TransitionImageLayout(TextureVkImpl& TextureVk, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange) { VERIFY(TextureVk.GetLayout() != NewLayout, "The texture is already transitioned to correct layout"); EnsureVkCmdBuffer(); @@ -1489,26 +1630,59 @@ namespace Diligent m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, SubresRange); } - void DeviceContextVkImpl::BufferMemoryBarrier(IBuffer *pBuffer, VkAccessFlags NewAccessFlags) + void DeviceContextVkImpl::BufferMemoryBarrier(IBuffer* pBuffer, VkAccessFlags NewAccessFlags) { VERIFY_EXPR(pBuffer != nullptr); auto pBuffVk = ValidatedCast(pBuffer); - if (!pBuffVk->CheckAccessFlags(NewAccessFlags)) + if (!pBuffVk->IsInKnownState()) + { + LOG_ERROR_MESSAGE("Failed to execute buffer memory barrier for buffer '", pBuffVk->GetDesc().Name, "' because the buffer state is unknown"); + return; + } + auto NewState = VkAccessFlagsToResourceStates(NewAccessFlags); + if ((pBuffVk->GetState() & NewState) != NewState) { - BufferMemoryBarrier(*pBuffVk, NewAccessFlags); + TransitionBufferState(*pBuffVk, RESOURCE_STATE_UNKNOWN, NewState, true); } } - void DeviceContextVkImpl::BufferMemoryBarrier(BufferVkImpl &BufferVk, VkAccessFlags NewAccessFlags) + void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE_STATE OldState, RESOURCE_STATE NewState, bool UpdateBufferState) { - VERIFY(!BufferVk.CheckAccessFlags(NewAccessFlags), "The buffer already has requested access flags"); + DEV_CHECK_ERR(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer"); + VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0); + EnsureVkCmdBuffer(); + if (OldState == RESOURCE_STATE_UNKNOWN) + { + if (BufferVk.IsInKnownState()) + { + OldState = BufferVk.GetState(); + } + else + { + LOG_ERROR_MESSAGE("Failed to transition the state of buffer '", BufferVk.GetDesc().Name, "' because the buffer state is unknown and is not explicitly specified"); + return; + } + } + else + { + if (BufferVk.IsInKnownState() && BufferVk.GetState() != OldState) + { + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(BufferVk.GetState()), " of buffer '", + BufferVk.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + " specified by the barrier"); + } + } + DEV_CHECK_ERR((OldState & NewState) != NewState, "The buffer is already in requested state"); - VERIFY(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer"); - VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0); auto vkBuff = BufferVk.GetVkBuffer(); - m_CommandBuffer.BufferMemoryBarrier(vkBuff, BufferVk.m_AccessFlags, NewAccessFlags); - BufferVk.SetAccessFlags(NewAccessFlags); + auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); + auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState); + m_CommandBuffer.BufferMemoryBarrier(vkBuff, OldAccessFlags, NewAccessFlags); + if (UpdateBufferState) + { + BufferVk.SetState(NewState); + } } VulkanDynamicAllocation DeviceContextVkImpl::AllocateDynamicSpace(Uint32 SizeInBytes, Uint32 Alignment) @@ -1522,6 +1696,50 @@ namespace Diligent void DeviceContextVkImpl::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers) { + if(BarrierCount == 0) + return; + + EnsureVkCmdBuffer(); + for(Uint32 i=0; i < BarrierCount; ++i) + { + const auto& Barrier = pResourceBarriers[i]; + DEV_CHECK_ERR( (Barrier.pTexture != nullptr) ^ (Barrier.pBuffer != nullptr), "Exactly one of pTexture or pBuffer must not be null"); + DEV_CHECK_ERR(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "New resource state can't be unknown"); + if (Barrier.pTexture) + { + auto* pTextureVkImpl = ValidatedCast(Barrier.pTexture); +#ifdef DEVELOPMENT + { + const auto& TexDesc = pTextureVkImpl->GetDesc(); + 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 == StateTransitionDesc::RemainingMipLevels || 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 == StateTransitionDesc::RemainingArraySlices || 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); + } +#endif + + VkImageSubresourceRange SubResRange; + SubResRange.aspectMask = 0; + SubResRange.baseMipLevel = Barrier.FirstMipLevel; + SubResRange.levelCount = (Barrier.MipLevelsCount == StateTransitionDesc::RemainingMipLevels) ? VK_REMAINING_MIP_LEVELS : Barrier.MipLevelsCount; + SubResRange.baseArrayLayer = Barrier.FirstArraySlice; + SubResRange.layerCount = (Barrier.ArraySliceCount == StateTransitionDesc::RemainingArraySlices) ? VK_REMAINING_ARRAY_LAYERS : Barrier.ArraySliceCount; + TransitionTextureState(*pTextureVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState, &SubResRange); + } + else + { + VERIFY_EXPR(Barrier.pBuffer != nullptr); + auto* pBufferVkImpl = ValidatedCast(Barrier.pBuffer); + TransitionBufferState(*pBufferVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); + } + } } } diff --git a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp index 9a60af88..8137e7cf 100644 --- a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp +++ b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp @@ -30,6 +30,7 @@ #include "TextureVkImpl.h" #include "MapHelper.h" #include "PlatformMisc.h" +#include "VulkanTypeConversions.h" #include "../../GraphicsTools/include/ShaderMacroHelper.h" #include "../../GraphicsTools/include/CommonlyUsedStates.h" @@ -197,6 +198,12 @@ namespace Diligent void GenerateMipsVkHelper::GenerateMips(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB) { auto* pTexVk = TexView.GetTexture(); + if (!pTexVk->IsInKnownState()) + { + LOG_ERROR_MESSAGE("Unable to generate mips for texture '", pTexVk->GetDesc().Name, "' because texture state is unknown"); + return; + } + const auto& TexDesc = pTexVk->GetDesc(); const auto& ViewDesc = TexView.GetDesc(); auto* pSrcMipVar = SRB.GetVariable(SHADER_TYPE_COMPUTE, "SrcMip"); @@ -220,14 +227,16 @@ namespace Diligent SubresRange.baseArrayLayer = 0; SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; - auto CurrLayout = pTexVk->GetLayout(); + const auto CurrState = pTexVk->GetState(); + const auto CurrLayout = ResourceStateToVkImageLayout(CurrState); // Transition the lowest mip level to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL SubresRange.baseMipLevel = 0; SubresRange.levelCount = 1; - if (CurrLayout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - Ctx.TransitionImageLayout(*pTexVk, CurrLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, SubresRange); - + if (CurrState != RESOURCE_STATE_SHADER_RESOURCE) + Ctx.TransitionTextureState(*pTexVk, CurrState, RESOURCE_STATE_SHADER_RESOURCE, false, &SubresRange); + VERIFY_EXPR(ResourceStateToVkImageLayout(RESOURCE_STATE_SHADER_RESOURCE) == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + for (uint32_t TopMip = 0; TopMip < TexDesc.MipLevels - 1; ) { // In Vulkan all subresources of a view must be transitioned to the same layout, so @@ -305,6 +314,7 @@ namespace Diligent } // All mip levels are now in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL state - pTexVk->SetLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + pTexVk->SetState(RESOURCE_STATE_SHADER_RESOURCE); + VERIFY_EXPR(pTexVk->GetLayout() == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } } diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp index 8eabf75f..9e1fb7ca 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp @@ -30,6 +30,7 @@ #include "TextureViewVkImpl.h" #include "TextureVkImpl.h" #include "SamplerVkImpl.h" +#include "VulkanTypeConversions.h" namespace Diligent { @@ -109,19 +110,26 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl *pCtxVkImpl) { case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: { - auto *pBufferVk = Res.pObject.RawPtr(); - VkAccessFlags RequiredAccessFlags = VK_ACCESS_UNIFORM_READ_BIT; - if (!pBufferVk->CheckAccessFlags(RequiredAccessFlags)) + auto* pBufferVk = Res.pObject.RawPtr(); + if (pBufferVk->IsInKnownState()) { - if (VerifyOnly) + RESOURCE_STATE RequiredState = RESOURCE_STATE_CONSTANT_BUFFER; + VERIFY_EXPR((ResourceStateFlagsToVkAccessFlags(RequiredState) & VK_ACCESS_UNIFORM_READ_BIT) == VK_ACCESS_UNIFORM_READ_BIT); + if (!pBufferVk->CheckState(RequiredState)) { - LOG_ERROR_MESSAGE("State of buffer \"", pBufferVk->GetDesc().Name, "\" is incorrect. Required access flags: ", - VulkanUtilities::VkAccessFlagsToString(RequiredAccessFlags), ". Actual access flags: ", - VulkanUtilities::VkAccessFlagsToString(pBufferVk->GetAccessFlags()), - ". Call TransitionShaderResources() or provide COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag to CommitShaderResources()"); + if (VerifyOnly) + { + LOG_ERROR_MESSAGE("State of buffer '", pBufferVk->GetDesc().Name, "' is incorrect. Required state: ", + GetResourceStateString(RequiredState), ". Actual state: ", + GetResourceStateString(pBufferVk->GetState()), + ". Call TransitionShaderResources() or provide COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag to CommitShaderResources()"); + } + else + { + pCtxVkImpl->TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + VERIFY_EXPR(pBufferVk->CheckAccessFlags(VK_ACCESS_UNIFORM_READ_BIT)); + } } - else - pCtxVkImpl->BufferMemoryBarrier(*pBufferVk, RequiredAccessFlags); } } break; @@ -130,23 +138,32 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl *pCtxVkImpl) case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: { - auto *pBuffViewVk = Res.pObject.RawPtr(); - auto *pBufferVk = ValidatedCast(pBuffViewVk->GetBuffer()); - VkAccessFlags RequiredAccessFlags = - Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer ? - VK_ACCESS_SHADER_READ_BIT : - (VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); - if (!pBufferVk->CheckAccessFlags(RequiredAccessFlags)) + auto* pBuffViewVk = Res.pObject.RawPtr(); + auto* pBufferVk = ValidatedCast(pBuffViewVk->GetBuffer()); + if (pBufferVk->IsInKnownState()) { - if (VerifyOnly) + RESOURCE_STATE RequiredState = (Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer) ? + RESOURCE_STATE_SHADER_RESOURCE : RESOURCE_STATE_UNORDERED_ACCESS; +#ifdef _DEBUG + VkAccessFlags RequiredAccessFlags = (Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer) ? + VK_ACCESS_SHADER_READ_BIT : (VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); + VERIFY_EXPR( (ResourceStateFlagsToVkAccessFlags(RequiredState) & RequiredAccessFlags) == RequiredAccessFlags); +#endif + if (!pBufferVk->CheckState(RequiredState)) { - LOG_ERROR_MESSAGE("State of buffer \"", pBufferVk->GetDesc().Name, "\" is incorrect. Required access flags: ", - VulkanUtilities::VkAccessFlagsToString(RequiredAccessFlags), ". Actual access flags: ", - VulkanUtilities::VkAccessFlagsToString(pBufferVk->GetAccessFlags()), - ". Call TransitionShaderResources() or provide COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag to CommitShaderResources()"); + if (VerifyOnly) + { + LOG_ERROR_MESSAGE("State of buffer '", pBufferVk->GetDesc().Name, "' is incorrect. Required state: ", + GetResourceStateString(RequiredState), ". Actual state: ", + GetResourceStateString(pBufferVk->GetState()), + ". Call TransitionShaderResources() or provide COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag to CommitShaderResources()"); + } + else + { + pCtxVkImpl->TransitionBufferState(*pBufferVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + VERIFY_EXPR(pBufferVk->CheckAccessFlags(RequiredAccessFlags)); + } } - else - pCtxVkImpl->BufferMemoryBarrier(*pBufferVk, RequiredAccessFlags); } } break; @@ -155,41 +172,53 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl *pCtxVkImpl) case SPIRVShaderResourceAttribs::ResourceType::SampledImage: case SPIRVShaderResourceAttribs::ResourceType::StorageImage: { - auto *pTextureViewVk = Res.pObject.RawPtr(); - auto *pTextureVk = ValidatedCast(pTextureViewVk->GetTexture()); - - // The image subresources for a storage image must be in the VK_IMAGE_LAYOUT_GENERAL layout in - // order to access its data in a shader (13.1.1) - // The image subresources for a sampled image or a combined image sampler must be in the - // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - // or VK_IMAGE_LAYOUT_GENERAL layout in order to access its data in a shader (13.1.3, 13.1.4). - VkImageLayout RequiredLayout; - if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage) - RequiredLayout = VK_IMAGE_LAYOUT_GENERAL; - else + auto* pTextureViewVk = Res.pObject.RawPtr(); + auto* pTextureVk = ValidatedCast(pTextureViewVk->GetTexture()); + if (pTextureVk->IsInKnownState()) { - if (pTextureVk->GetDesc().BindFlags & BIND_DEPTH_STENCIL) + // The image subresources for a storage image must be in the VK_IMAGE_LAYOUT_GENERAL layout in + // order to access its data in a shader (13.1.1) + // The image subresources for a sampled image or a combined image sampler must be in the + // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + // or VK_IMAGE_LAYOUT_GENERAL layout in order to access its data in a shader (13.1.3, 13.1.4). + RESOURCE_STATE RequiredState; + if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage) { - // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL must only be used as a read - only depth / stencil attachment - // in a VkFramebuffer and/or as a read - only image in a shader (which can be read as a sampled image, combined - // image / sampler and /or input attachment). This layout is valid only for image subresources of images created - // with the VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT usage bit enabled. (11.4) - RequiredLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + RequiredState = RESOURCE_STATE_UNORDERED_ACCESS; + VERIFY_EXPR(ResourceStateToVkImageLayout(RequiredState) == VK_IMAGE_LAYOUT_GENERAL); } else - RequiredLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - if (pTextureVk->GetLayout() != RequiredLayout) - { - if (VerifyOnly) { - LOG_ERROR_MESSAGE("State of texture \"", pTextureVk->GetDesc().Name, "\" is incorrect. Required layout: ", - VulkanUtilities::VkImageLayoutToString(RequiredLayout), ". Actual layout: ", - VulkanUtilities::VkImageLayoutToString(pTextureVk->GetLayout()), - ". Call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()"); + if (pTextureVk->GetDesc().BindFlags & BIND_DEPTH_STENCIL) + { + // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL must only be used as a read - only depth / stencil attachment + // in a VkFramebuffer and/or as a read - only image in a shader (which can be read as a sampled image, combined + // image / sampler and /or input attachment). This layout is valid only for image subresources of images created + // with the VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT usage bit enabled. (11.4) + RequiredState = RESOURCE_STATE_DEPTH_READ; + VERIFY_EXPR(ResourceStateToVkImageLayout(RequiredState) == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); + } + else + { + RequiredState = RESOURCE_STATE_SHADER_RESOURCE; + VERIFY_EXPR(ResourceStateToVkImageLayout(RequiredState) == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + } + + if (!pTextureVk->CheckState(RequiredState)) + { + if (VerifyOnly) + { + LOG_ERROR_MESSAGE("State of texture '", pTextureVk->GetDesc().Name, "' is incorrect. Required state: ", + GetResourceStateString(RequiredState), ". Actual state: ", + GetResourceStateString(pTextureVk->GetState()), + ". Call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()"); + } + else + { + pCtxVkImpl->TransitionTextureState(*pTextureVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + } } - else - pCtxVkImpl->TransitionImageLayout(*pTextureVk, RequiredLayout); } } break; @@ -287,7 +316,7 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteIn } else { - LOG_ERROR_MESSAGE("No sampler assigned to texture view \"", pTexViewVk->GetDesc().Name, "\""); + LOG_ERROR_MESSAGE("No sampler assigned to texture view '", pTexViewVk->GetDesc().Name, "'"); } } DescrImgInfo.imageView = pTexViewVk->GetVulkanImageView(); diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index fb11548b..f49e6629 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -137,8 +137,7 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, // while using this layout, and the transition away from this layout will preserve that data. // If it is VK_IMAGE_LAYOUT_UNDEFINED, then the contents of the data are considered to be undefined, // and the transition away from this layout is not guaranteed to preserve that data. - m_CurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; - ImageCI.initialLayout = m_CurrentLayout; + ImageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; bool bInitializeTexture = (InitData.pSubResources != nullptr && InitData.NumSubresources > 0); @@ -190,8 +189,10 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; SubresRange.baseMipLevel = 0; SubresRange.levelCount = VK_REMAINING_MIP_LEVELS; - VulkanUtilities::VulkanCommandBuffer::TransitionImageLayout(vkCmdBuff, m_VulkanImage, m_CurrentLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange); - m_CurrentLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + VulkanUtilities::VulkanCommandBuffer::TransitionImageLayout(vkCmdBuff, m_VulkanImage, ImageCI.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange); + SetState(RESOURCE_STATE_COPY_DEST); + const auto CurrentLayout = GetLayout(); + VERIFY_EXPR(CurrentLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); if(bInitializeTexture) { @@ -334,7 +335,7 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, // Copy commands MUST be recorded outside of a render pass instance. This is OK here // as copy will be the only command in the cmd buffer vkCmdCopyBufferToImage(vkCmdBuff, StagingBuffer, m_VulkanImage, - m_CurrentLayout, // dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.4) + CurrentLayout, // dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.4) static_cast(Regions.size()), Regions.data()); Uint32 QueueIndex = 0; @@ -360,7 +361,7 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, { VkClearColorValue ClearColor = {}; vkCmdClearColorImage(vkCmdBuff, m_VulkanImage, - m_CurrentLayout, // must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + CurrentLayout, // must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &ClearColor, 1, &Subresource); } } @@ -369,7 +370,7 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, { VkClearDepthStencilValue ClearValue = {}; vkCmdClearDepthStencilImage(vkCmdBuff, m_VulkanImage, - m_CurrentLayout, // must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + CurrentLayout, // must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &ClearValue, 1, &Subresource); } else @@ -433,6 +434,8 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, } VERIFY_EXPR(m_MipLevelSRV.size() == m_Desc.MipLevels); } + + VERIFY_EXPR(IsInKnownState()); } TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters, @@ -752,4 +755,14 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc return LogicalDevice.CreateImageView(ImageViewCI, ViewName.c_str()); } +void TextureVkImpl::SetLayout(VkImageLayout Layout) +{ + SetState(VkImageLayoutToResourceState(Layout)); +} + +VkImageLayout TextureVkImpl::GetLayout()const +{ + return ResourceStateToVkImageLayout(GetState()); +} + } diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp index 75c23615..ad94cbdb 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp @@ -1184,9 +1184,90 @@ VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags) return AccessFlags; } +RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlagBits AccessFlagBit) +{ + VERIFY((AccessFlagBit & (AccessFlagBit-1)) == 0, "Single access flag bit is expected"); + + switch(AccessFlagBit) + { + case VK_ACCESS_INDIRECT_COMMAND_READ_BIT: return RESOURCE_STATE_INDIRECT_ARGUMENT; + case VK_ACCESS_INDEX_READ_BIT: return RESOURCE_STATE_INDEX_BUFFER; + case VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: return RESOURCE_STATE_VERTEX_BUFFER; + case VK_ACCESS_UNIFORM_READ_BIT: return RESOURCE_STATE_CONSTANT_BUFFER; + case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_SHADER_READ_BIT: return RESOURCE_STATE_SHADER_RESOURCE; + case VK_ACCESS_SHADER_WRITE_BIT: return RESOURCE_STATE_UNORDERED_ACCESS; + case VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: return RESOURCE_STATE_RENDER_TARGET; + case VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: return RESOURCE_STATE_RENDER_TARGET; + case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT: return RESOURCE_STATE_DEPTH_READ; + case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: return RESOURCE_STATE_DEPTH_WRITE; + case VK_ACCESS_TRANSFER_READ_BIT: return RESOURCE_STATE_COPY_SOURCE; + case VK_ACCESS_TRANSFER_WRITE_BIT: return RESOURCE_STATE_COPY_DEST; + case VK_ACCESS_HOST_READ_BIT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_HOST_WRITE_BIT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_MEMORY_READ_BIT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_MEMORY_WRITE_BIT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX: return RESOURCE_STATE_UNKNOWN; + default: + UNEXPECTED("Unknown access flag"); + return RESOURCE_STATE_UNKNOWN; + } +} + + +class VkAccessFlagBitPosToResourceState +{ +public: + VkAccessFlagBitPosToResourceState() + { + for (Uint32 bit=0; bit < MaxFlagBitPos; ++bit) + { + FlagBitPosToResourceState[bit] = VkAccessFlagsToResourceStates(static_cast(1< FlagBitPosToResourceState; +}; + + +RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlags AccessFlags) +{ + static const VkAccessFlagBitPosToResourceState BitPosToState; + Uint32 State = 0; + while (AccessFlags != 0) + { + auto lsb = PlatformMisc::GetLSB(AccessFlags); + State |= BitPosToState(lsb); + AccessFlags &= ~(1<(State); +} + + VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag) { + if(StateFlag == RESOURCE_STATE_UNKNOWN) + { + return VK_IMAGE_LAYOUT_UNDEFINED; + } // Currently not used: //VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL //VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL @@ -1216,9 +1297,34 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag) case RESOURCE_STATE_PRESENT: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; default: - UNEXPECTED("Unexpected resource state flag"); + UNEXPECTED("Unexpected resource state flag (", StateFlag, ")"); return VK_IMAGE_LAYOUT_UNDEFINED; } } - + +RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout) +{ + static_assert(RESOURCE_STATE_MAX_BIT == 0x8000, "This function must be updated to handle new resource state flag"); + switch(Layout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: return RESOURCE_STATE_UNDEFINED; + case VK_IMAGE_LAYOUT_GENERAL: return RESOURCE_STATE_UNORDERED_ACCESS; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return RESOURCE_STATE_RENDER_TARGET; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: return RESOURCE_STATE_DEPTH_WRITE; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: return RESOURCE_STATE_DEPTH_READ; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return RESOURCE_STATE_SHADER_RESOURCE; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return RESOURCE_STATE_COPY_SOURCE; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return RESOURCE_STATE_COPY_DEST; + case VK_IMAGE_LAYOUT_PREINITIALIZED: UNEXPECTED("This layout is not supported"); return RESOURCE_STATE_UNDEFINED; + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: UNEXPECTED("This layout is not supported"); return RESOURCE_STATE_UNDEFINED; + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: UNEXPECTED("This layout is not supported"); return RESOURCE_STATE_UNDEFINED; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: return RESOURCE_STATE_PRESENT; + case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR: UNEXPECTED("This layout is not supported"); return RESOURCE_STATE_UNDEFINED; + case VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV: UNEXPECTED("This layout is not supported"); return RESOURCE_STATE_UNDEFINED; + default: + UNEXPECTED("Unknown image layout (", Layout, ")"); + return RESOURCE_STATE_UNDEFINED; + } +} + } -- cgit v1.2.3