summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2018-11-20 05:26:49 +0000
committerEgor Yusov <egor.yusov@gmail.com>2018-11-20 05:26:49 +0000
commit5ea80a116bc5ff82d8ef10243f7fba103a4d0961 (patch)
treecb5dc3fc3345ce6a77ba066539d571e5fde9a8e9 /Graphics/GraphicsEngineVulkan
parentAdded explicit resource state transitions to the API; implemented in D3D12 (diff)
downloadDiligentCore-5ea80a116bc5ff82d8ef10243f7fba103a4d0961.tar.gz
DiligentCore-5ea80a116bc5ff82d8ef10243f7fba103a4d0961.zip
Implemented explicit layout transitions in Vulkan backend
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h15
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h43
-rw-r--r--Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h10
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h3
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h2
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/TextureVk.h11
-rw-r--r--Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp53
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp348
-rw-r--r--Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp20
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp137
-rw-r--r--Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp27
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp110
12 files changed, 600 insertions, 179 deletions
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<Vk_SUBRESOURCE_DATA> &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<std::unique_ptr<TextureViewVkImpl, STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator> > > 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>(
+ 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<BufferVkImpl>();
- 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<TextureVkImpl>(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<TextureVkImpl>(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<TextureViewVkImpl>();
- auto* pDepthBuffer = pDSVVk->GetTexture();
- TransitionImageLayout(pDepthBuffer, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ auto* pDepthBufferVk = ValidatedCast<TextureVkImpl>(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<TextureViewVkImpl>(pRTV);
- auto* pRenderTarget = pRTVVk->GetTexture();
- TransitionImageLayout(pRenderTarget, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ auto* pRenderTargetVk = ValidatedCast<TextureVkImpl>(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<Uint32>(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<TextureVkImpl>(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<BufferVkImpl>(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<TextureVkImpl>(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<BufferVkImpl>(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<TextureVkImpl>();
+ 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<BufferVkImpl>();
- VkAccessFlags RequiredAccessFlags = VK_ACCESS_UNIFORM_READ_BIT;
- if (!pBufferVk->CheckAccessFlags(RequiredAccessFlags))
+ auto* pBufferVk = Res.pObject.RawPtr<BufferVkImpl>();
+ 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<BufferViewVkImpl>();
- auto *pBufferVk = ValidatedCast<BufferVkImpl>(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<BufferViewVkImpl>();
+ auto* pBufferVk = ValidatedCast<BufferVkImpl>(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<TextureViewVkImpl>();
- auto *pTextureVk = ValidatedCast<TextureVkImpl>(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<TextureViewVkImpl>();
+ auto* pTextureVk = ValidatedCast<TextureVkImpl>(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<uint32_t>(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<VkAccessFlagBits>(1<<bit));
+ }
+ }
+
+ RESOURCE_STATE operator()(Uint32 BitPos)const
+ {
+ VERIFY(BitPos <= MaxFlagBitPos, "Resource state flag bit position (", BitPos, ") exceeds max bit position (", MaxFlagBitPos, ")");
+ return FlagBitPosToResourceState[BitPos];
+ }
+
+private:
+ static constexpr Uint32 MaxFlagBitPos = 20;
+ std::array<RESOURCE_STATE, MaxFlagBitPos + 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<<lsb);
+ }
+ return static_cast<RESOURCE_STATE>(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;
+ }
+}
+
}