From 401ddeeee1b072f69c808c42d5dc2e078a4a10ea Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Wed, 18 Apr 2018 22:26:22 -0700 Subject: Added image layout transitioning function --- Graphics/GraphicsEngineVulkan/CMakeLists.txt | 1 + .../include/CommandListVkImpl.h | 8 +- .../include/DeviceContextVkImpl.h | 8 +- .../GraphicsEngineVulkan/include/TextureVkImpl.h | 7 +- .../include/VulkanUtilities/VulkanCommandBuffer.h | 74 +++-- .../src/DeviceContextVkImpl.cpp | 64 ++-- .../GraphicsEngineVulkan/src/TextureVkImpl.cpp | 22 +- .../src/VulkanUtilities/VulkanCommandBuffer.cpp | 321 +++++++++++++++++++++ 8 files changed, 432 insertions(+), 73 deletions(-) create mode 100644 Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index 322f90b3..a340fedd 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -88,6 +88,7 @@ set(SRC ) set(VULKAN_UTILS_SRC + src/VulkanUtilities/VulkanCommandBuffer.cpp src/VulkanUtilities/VulkanCommandBufferPool.cpp src/VulkanUtilities/VulkanDebug.cpp src/VulkanUtilities/VulkanFencePool.cpp diff --git a/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.h b/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.h index d42700d8..645218dc 100644 --- a/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.h @@ -24,7 +24,7 @@ #pragma once /// \file -/// Declaration of Diligent::CommandListD3D12Impl class +/// Declaration of Diligent::CommandListVkImpl class #include "CommandListBase.h" @@ -32,17 +32,17 @@ namespace Diligent { /// Implementation of the Diligent::ICommandList interface -class CommandListD3D12Impl : public CommandListBase +class CommandListVkImpl : public CommandListBase { public: typedef CommandListBase TCommandListBase; - CommandListD3D12Impl(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, class CommandContext* pCmdContext) : + CommandListVkImpl(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, class CommandContext* pCmdContext) : TCommandListBase(pRefCounters, pDevice), m_pCmdContext(pCmdContext) { } - ~CommandListD3D12Impl() + ~CommandListVkImpl() { VERIFY(m_pCmdContext == nullptr, "Destroying command list that was never executed"); } diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h index 4564b331..9652fafa 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h @@ -113,7 +113,7 @@ public: Uint32 GetContextId()const{return m_ContextId;} #endif - size_t GetNumCommandsInCtx()const { return m_NumCommandsInCurCtx; } + size_t GetNumCommandsInCtx()const { return m_State.NumCommands; } private: void CommitRenderPassAndFramebuffer(); @@ -124,7 +124,6 @@ private: void CommitViewports(); void CommitScissorRects(); - void Flush(bool RequestNewCmdCtx); #if 0 friend class SwapChainVkImpl; #endif @@ -133,6 +132,7 @@ private: VulkanUtilities::VulkanCommandBuffer m_CommandBuffer; + const Uint32 m_NumCommandsToFlush = 192; struct ContextState { /// Flag indicating if currently committed vertex buffers are up to date @@ -140,10 +140,10 @@ private: /// Flag indicating if currently committed index buffer is up to date bool CommittedIBUpToDate = false; + + Uint32 NumCommands = 0; }m_State; - Uint32 m_NumCommandsInCurCtx = 0; - const Uint32 m_NumCommandsToFlush = 192; #if 0 CComPtr m_CommittedVkIndexBuffer; VALUE_TYPE m_CommittedIBFormat = VT_UNDEFINED; diff --git a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h index ac10e686..223ca9bd 100644 --- a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h @@ -96,9 +96,13 @@ public: { return m_TexArraySRV.GetCpuHandle(); } +*/ + + void SetLayout(VkImageLayout NewLayout){ m_CurrentLayout = NewLayout;} + VkImageLayout GetLayout()const{return m_CurrentLayout;} protected: -*/ + void CreateViewInternal( const struct TextureViewDesc &ViewDesc, ITextureView **ppView, bool bIsDefaultView )override; //void PrepareVkInitData(const TextureData &InitData, Uint32 NumSubresources, std::vector &VkInitData); @@ -114,6 +118,7 @@ protected: */ VulkanUtilities::ImageWrapper m_VulkanImage; VulkanUtilities::DeviceMemoryWrapper m_ImageMemory; + VkImageLayout m_CurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h index 9af47e44..c2fff6a2 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h @@ -24,6 +24,7 @@ #pragma once #include "vulkan.h" +#include "DebugUtilities.h" namespace VulkanUtilities { @@ -83,60 +84,60 @@ namespace VulkanUtilities ); } - void Draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) + void Draw(uint32_t VertexCount, uint32_t InstanceCount, uint32_t FirstVertex, uint32_t FirstInstance) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); VERIFY(m_State.RenderPass != VK_NULL_HANDLE, "vkCmdDraw() must be called inside render pass (19.3)"); VERIFY(m_State.GraphicsPipeline != VK_NULL_HANDLE, "No graphics pipeline bound"); - vkCmdDraw(m_VkCmdBuffer, vertexCount, instanceCount, firstVertex, firstInstance); + vkCmdDraw(m_VkCmdBuffer, VertexCount, InstanceCount, FirstVertex, FirstInstance); } - void DrawIndexed(uint32_t indexCount,uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) + void DrawIndexed(uint32_t IndexCount,uint32_t InstanceCount, uint32_t FirstIndex, int32_t VertexOffset, uint32_t FirstInstance) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); VERIFY(m_State.RenderPass != VK_NULL_HANDLE, "vkCmdDrawIndexed() must be called inside render pass (19.3)"); VERIFY(m_State.GraphicsPipeline != VK_NULL_HANDLE, "No graphics pipeline bound"); VERIFY(m_State.IndexBuffer != VK_NULL_HANDLE, "No index buffer bound"); - vkCmdDrawIndexed(m_VkCmdBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); + vkCmdDrawIndexed(m_VkCmdBuffer, IndexCount, InstanceCount, FirstIndex, VertexOffset, FirstInstance); } - void DrawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) + void DrawIndirect(VkBuffer Buffer, VkDeviceSize Offset, uint32_t DrawCount, uint32_t Stride) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); VERIFY(m_State.RenderPass != VK_NULL_HANDLE, "vkCmdDrawIndirect() must be called inside render pass (19.3)"); VERIFY(m_State.GraphicsPipeline != VK_NULL_HANDLE, "No graphics pipeline bound"); - vkCmdDrawIndirect(m_VkCmdBuffer, buffer, offset, drawCount, stride); + vkCmdDrawIndirect(m_VkCmdBuffer, Buffer, Offset, DrawCount, Stride); } - void DrawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) + void DrawIndexedIndirect(VkBuffer Buffer, VkDeviceSize Offset, uint32_t DrawCount, uint32_t Stride) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); VERIFY(m_State.RenderPass != VK_NULL_HANDLE, "vkCmdDrawIndirect() must be called inside render pass (19.3)"); VERIFY(m_State.GraphicsPipeline != VK_NULL_HANDLE, "No graphics pipeline bound"); VERIFY(m_State.IndexBuffer != VK_NULL_HANDLE, "No index buffer bound"); - vkCmdDrawIndexedIndirect(m_VkCmdBuffer, buffer, offset, drawCount, stride); + vkCmdDrawIndexedIndirect(m_VkCmdBuffer, Buffer, Offset, DrawCount, Stride); } - void Dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) + void Dispatch(uint32_t GroupCountX, uint32_t GroupCountY, uint32_t GroupCountZ) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); VERIFY(m_State.RenderPass == VK_NULL_HANDLE, "vkCmdDispatch() must be called outside of render pass (27)"); VERIFY(m_State.ComputePipeline != VK_NULL_HANDLE, "No compute pipeline bound"); - vkCmdDispatch(m_VkCmdBuffer, groupCountX, groupCountY, groupCountZ); + vkCmdDispatch(m_VkCmdBuffer, GroupCountX, GroupCountY, GroupCountZ); } - void DispatchIndirect(VkBuffer buffer, VkDeviceSize offset) + void DispatchIndirect(VkBuffer Buffer, VkDeviceSize Offset) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); VERIFY(m_State.RenderPass == VK_NULL_HANDLE, "vkCmdDispatchIndirect() must be called outside of render pass (27)"); VERIFY(m_State.ComputePipeline != VK_NULL_HANDLE, "No compute pipeline bound"); - vkCmdDispatchIndirect(m_VkCmdBuffer, buffer, offset); + vkCmdDispatchIndirect(m_VkCmdBuffer, Buffer, Offset); } void BeginRenderPass(VkRenderPass RenderPass, VkFramebuffer Framebuffer, uint32_t FramebufferWidth, uint32_t FramebufferHeight) @@ -206,39 +207,62 @@ namespace VulkanUtilities } } - void SetViewports(uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports) + void SetViewports(uint32_t FirstViewport, uint32_t ViewportCount, const VkViewport* pViewports) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); - vkCmdSetViewport(m_VkCmdBuffer, firstViewport, viewportCount, pViewports); + vkCmdSetViewport(m_VkCmdBuffer, FirstViewport, ViewportCount, pViewports); } - void SetScissorRects(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors) + void SetScissorRects(uint32_t FirstScissor, uint32_t ScissorCount, const VkRect2D* pScissors) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); - vkCmdSetScissor(m_VkCmdBuffer, firstScissor, scissorCount, pScissors); + vkCmdSetScissor(m_VkCmdBuffer, FirstScissor, ScissorCount, pScissors); } - void SetStencilReference(uint32_t reference) + void SetStencilReference(uint32_t Reference) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); - vkCmdSetStencilReference(m_VkCmdBuffer, VK_STENCIL_FRONT_AND_BACK, reference); + vkCmdSetStencilReference(m_VkCmdBuffer, VK_STENCIL_FRONT_AND_BACK, Reference); } - void SetBlendConstants(const float blendConstants[4]) + void SetBlendConstants(const float BlendConstants[4]) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); - vkCmdSetBlendConstants(m_VkCmdBuffer, blendConstants); + vkCmdSetBlendConstants(m_VkCmdBuffer, BlendConstants); } - void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) + void BindIndexBuffer(VkBuffer Buffer, VkDeviceSize Offset, VkIndexType IndexType) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); - vkCmdBindIndexBuffer(m_VkCmdBuffer, buffer, offset, indexType); - m_State.IndexBuffer = buffer; - m_State.IndexBufferOffset = offset; - m_State.IndexType = indexType; + vkCmdBindIndexBuffer(m_VkCmdBuffer, Buffer, Offset, IndexType); + m_State.IndexBuffer = Buffer; + m_State.IndexBufferOffset = Offset; + m_State.IndexType = IndexType; } + static void TransitionImageLayout(VkCommandBuffer CmdBuffer, + VkImage Image, + VkImageAspectFlags AspectMask, + VkImageLayout OldLayout, + VkImageLayout NewLayout, + const VkImageSubresourceRange& SubresRange, + VkPipelineStageFlags SrcStages, + VkPipelineStageFlags DestStages); + + void TransitionImageLayout(VkImage Image, + VkImageAspectFlags AspectMask, + VkImageLayout OldLayout, + VkImageLayout NewLayout, + const VkImageSubresourceRange& SubresRange, + VkPipelineStageFlags SrcStages, + VkPipelineStageFlags DestStages) + { + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + TransitionImageLayout(m_VkCmdBuffer, Image, AspectMask, OldLayout, NewLayout, SubresRange, SrcStages, DestStages); + } + + void FlushBarriers(); + void SetVkCmdBuffer(VkCommandBuffer VkCmdBuffer) { m_VkCmdBuffer = VkCmdBuffer; diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index d144f115..22200917 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -39,12 +39,8 @@ namespace Diligent DeviceContextVkImpl::DeviceContextVkImpl( IReferenceCounters *pRefCounters, RenderDeviceVkImpl *pDeviceVkImpl, bool bIsDeferred, const EngineVkAttribs &Attribs, Uint32 ContextId) : TDeviceContextBase(pRefCounters, pDeviceVkImpl, bIsDeferred), //m_pUploadHeap(pDeviceVkImpl->RequestUploadHeap() ), - m_NumCommandsInCurCtx(0), m_NumCommandsToFlush(bIsDeferred ? std::numeric_limits::max() : Attribs.NumCommandsToFlushCmdBuffer), - /*m_pCurrCmdCtx(pDeviceVkImpl->AllocateCommandContext()), - m_CommittedIBFormat(VT_UNDEFINED), - m_CommittedVkIndexDataStartOffset(0), - m_MipsGenerator(pDeviceVkImpl->GetVkDevice()), + /*m_MipsGenerator(pDeviceVkImpl->GetVkDevice()), m_CmdListAllocator(GetRawAllocator(), sizeof(CommandListVkImpl), 64 ), m_ContextId(ContextId),*/ m_CmdPool(pDeviceVkImpl->GetLogicalDevice().GetSharedPtr(), pDeviceVkImpl->GetCmdQueue()->GetQueueFamilyIndex(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT) @@ -83,10 +79,10 @@ namespace Diligent } else { - if (m_NumCommandsInCurCtx != 0) + if (m_State.NumCommands != 0) LOG_WARNING_MESSAGE("Flusing outstanding commands from the device context being destroyed. This may result in synchronization errors"); - Flush(false); + Flush(); } } @@ -96,7 +92,7 @@ namespace Diligent { // Make sure that the number of commands in the context is at least one, // so that the context cannot be disposed by Flush() - m_NumCommandsInCurCtx = m_NumCommandsInCurCtx != 0 ? m_NumCommandsInCurCtx : 1; + m_State.NumCommands = m_State.NumCommands != 0 ? m_State.NumCommands : 1; if (m_CommandBuffer.GetVkCmdBuffer() == VK_NULL_HANDLE) { auto pDeviceVkImpl = m_pDevice.RawPtr(); @@ -126,9 +122,9 @@ namespace Diligent } // Never flush deferred context! - if (!m_bIsDeferred && m_NumCommandsInCurCtx >= m_NumCommandsToFlush) + if (!m_bIsDeferred && m_State.NumCommands >= m_NumCommandsToFlush) { - Flush(true); + Flush(); } auto *pPipelineStateVk = ValidatedCast(pPipelineState); @@ -433,7 +429,7 @@ namespace Diligent GraphCtx.Draw(DrawAttribs.NumVertices, DrawAttribs.NumInstances, DrawAttribs.StartVertexLocation, DrawAttribs.FirstInstanceLocation ); } #endif - ++m_NumCommandsInCurCtx; + ++m_State.NumCommands; } void DeviceContextVkImpl::DispatchCompute( const DispatchComputeAttribs &DispatchAttrs ) @@ -491,7 +487,7 @@ namespace Diligent else ComputeCtx.Dispatch(DispatchAttrs.ThreadGroupCountX, DispatchAttrs.ThreadGroupCountY, DispatchAttrs.ThreadGroupCountZ); #endif - ++m_NumCommandsInCurCtx; + ++m_State.NumCommands; } void DeviceContextVkImpl::ClearDepthStencil( ITextureView *pView, Uint32 ClearFlags, float fDepth, Uint8 Stencil ) @@ -525,7 +521,7 @@ namespace Diligent // Viewport and scissor settings are not applied?? RequestCmdContext()->AsGraphicsContext().ClearDepthStencil( pDSVVk, VkClearFlags, fDepth, Stencil ); #endif - ++m_NumCommandsInCurCtx; + ++m_State.NumCommands; } void DeviceContextVkImpl::ClearRenderTarget( ITextureView *pView, const float *RGBA ) @@ -561,17 +557,19 @@ namespace Diligent // Viewport and scissor settings are not applied?? RequestCmdContext()->AsGraphicsContext().ClearRenderTarget( pVkRTV, RGBA ); #endif - ++m_NumCommandsInCurCtx; + ++m_State.NumCommands; } - void DeviceContextVkImpl::Flush(bool RequestNewCmdCtx) + void DeviceContextVkImpl::Flush() { + VERIFY(!m_bIsDeferred, "Flush() should only be called for immediate contexts"); + auto pDeviceVkImpl = m_pDevice.RawPtr(); auto vkCmdBuff = m_CommandBuffer.GetVkCmdBuffer(); if(vkCmdBuff != VK_NULL_HANDLE ) { VERIFY(!m_bIsDeferred, "Deferred contexts cannot execute command lists directly"); - if (m_NumCommandsInCurCtx != 0) + if (m_State.NumCommands != 0) { //m_pCurrCmdCtx->FlushResourceBarriers(); pDeviceVkImpl->ExecuteCommandBuffer(vkCmdBuff, true); @@ -579,20 +577,10 @@ namespace Diligent DisposeVkCmdBuffer(); } - m_NumCommandsInCurCtx = 0; - - if(RequestNewCmdCtx) - EnsureVkCmdBuffer(); - + m_State.NumCommands = 0; m_pPipelineState.Release(); } - void DeviceContextVkImpl::Flush() - { - VERIFY(!m_bIsDeferred, "Flush() should only be called for immediate contexts"); - Flush(true); - } - void DeviceContextVkImpl::SetVertexBuffers( Uint32 StartSlot, Uint32 NumBuffersSet, IBuffer **ppBuffers, Uint32 *pStrides, Uint32 *pOffsets, Uint32 Flags ) { TDeviceContextBase::SetVertexBuffers( StartSlot, NumBuffersSet, ppBuffers, pStrides, pOffsets, Flags ); @@ -601,7 +589,7 @@ namespace Diligent void DeviceContextVkImpl::InvalidateState() { - if (m_NumCommandsInCurCtx != 0) + if (m_State.NumCommands != 0) LOG_WARNING_MESSAGE("Invalidating context that has outstanding commands in it. Call Flush() to submit commands for execution"); TDeviceContextBase::InvalidateState(); @@ -630,7 +618,7 @@ namespace Diligent VkViewports[vp].maxDepth = m_Viewports[vp].MaxDepth; } EnsureVkCmdBuffer(); - // TODO: reinterpret_cast m_Viewports to m_Viewports? + // TODO: reinterpret_cast m_Viewports to VkViewports? m_CommandBuffer.SetViewports(0, m_NumViewports, VkViewports); } @@ -744,7 +732,7 @@ namespace Diligent auto *pVkBuff = pBuffVk->GetVkBuffer(DstBuffDataStartByteOffset, m_ContextId); VERIFY(DstBuffDataStartByteOffset == 0, "Dst buffer must not be suballocated"); pCmdCtx->GetCommandList()->CopyBufferRegion( pVkBuff, DstOffset + DstBuffDataStartByteOffset, Allocation.pBuffer, Allocation.Offset, NumBytes); - ++m_NumCommandsInCurCtx; + ++m_State.NumCommands; } void DeviceContextVkImpl::UpdateBufferRegion(BufferVkImpl *pBuffVk, const void *pData, Uint64 DstOffset, Uint64 NumBytes) @@ -772,7 +760,7 @@ namespace Diligent size_t SrcDataStartByteOffset; auto *pVkSrcBuff = pSrcBuffVk->GetVkBuffer(SrcDataStartByteOffset, m_ContextId); pCmdCtx->GetCommandList()->CopyBufferRegion( pVkDstBuff, DstOffset + DstDataStartByteOffset, pVkSrcBuff, SrcOffset+SrcDataStartByteOffset, NumBytes); - ++m_NumCommandsInCurCtx; + ++m_State.NumCommands; } void DeviceContextVkImpl::CopyTextureRegion(TextureVkImpl *pSrcTexture, Uint32 SrcSubResIndex, const Vk_BOX *pVkSrcBox, @@ -793,7 +781,7 @@ namespace Diligent SrcLocation.SubresourceIndex = SrcSubResIndex; pCmdCtx->GetCommandList()->CopyTextureRegion( &DstLocation, DstX, DstY, DstZ, &SrcLocation, pVkSrcBox); - ++m_NumCommandsInCurCtx; + ++m_State.NumCommands; } void DeviceContextVkImpl::CopyTextureRegion(IBuffer *pSrcBuffer, Uint32 SrcStride, Uint32 SrcDepthStride, class TextureVkImpl *pTextureVk, Uint32 DstSubResIndex, const Box &DstBox) @@ -848,7 +836,7 @@ namespace Diligent static_cast( DstBox.MinZ ), &SrcLocation, &VkSrcBox); - ++m_NumCommandsInCurCtx; + ++m_State.NumCommands; if (StateTransitionRequired) { @@ -862,7 +850,7 @@ namespace Diligent #if 0 auto *pCtx = RequestCmdContext(); m_MipsGenerator.GenerateMips(m_pDevice.RawPtr(), pTexView, *pCtx); - ++m_NumCommandsInCurCtx; + ++m_State.NumCommands; #endif } @@ -873,7 +861,11 @@ namespace Diligent (m_pDevice, m_pCurrCmdCtx) ); pCmdListVk->QueryInterface( IID_CommandList, reinterpret_cast(ppCommandList) ); m_pCurrCmdCtx = nullptr; - Flush(true); + //Flush(); + + m_CommandBuffer.Reset(); + m_State = ContextState{}; + m_pPipelineState.Release(); InvalidateState(); #endif @@ -888,7 +880,7 @@ namespace Diligent } #if 0 // First execute commands in this context - Flush(true); + Flush(); InvalidateState(); diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index e573e406..7b4dfecf 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -121,19 +121,35 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters *pRefCounters, ImageCI.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; if (m_Desc.BindFlags & BIND_RENDER_TARGET) - ImageCI.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + { + // VK_IMAGE_USAGE_TRANSFER_DST_BIT is required for vkCmdClearColorImage() + ImageCI.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } if (m_Desc.BindFlags & BIND_DEPTH_STENCIL) - ImageCI.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + { + // VK_IMAGE_USAGE_TRANSFER_DST_BIT is required for vkCmdClearDepthStencilImage() + ImageCI.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } if ((m_Desc.BindFlags & BIND_UNORDERED_ACCESS) || (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS)) + { ImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT; + } if (m_Desc.BindFlags & BIND_SHADER_RESOURCE) + { ImageCI.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + } ImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ImageCI.queueFamilyIndexCount = 0; ImageCI.pQueueFamilyIndices = nullptr; - ImageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + // initialLayout must be either VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED (11.4) + // If it is VK_IMAGE_LAYOUT_PREINITIALIZED, then the image data can be preinitialized by the host + // 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; #if 0 Desc.Flags = Vk_RESOURCE_FLAG_NONE; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp new file mode 100644 index 00000000..3f5710a2 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp @@ -0,0 +1,321 @@ +/* Copyright 2015-2018 Egor Yusov +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. +* +* In no event and under no legal theory, whether in tort (including negligence), +* contract, or otherwise, unless required by applicable law (such as deliberate +* and grossly negligent acts) or agreed to in writing, shall any Contributor be +* liable for any damages, including any direct, indirect, special, incidental, +* or consequential damages of any character arising as a result of this License or +* out of the use or inability to use the software (including but not limited to damages +* for loss of goodwill, work stoppage, computer failure or malfunction, or any and +* all other commercial damages or losses), even if such Contributor has been advised +* of the possibility of such damages. +*/ +#include + +#include "VulkanUtilities/VulkanCommandBuffer.h" + +namespace VulkanUtilities +{ + +static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags AccessFlags) +{ + // 6.1.3 + VkPipelineStageFlags Stages = 0; + + while(AccessFlags != 0) + { + VkAccessFlagBits AccessFlag = static_cast( AccessFlags & (~(AccessFlags-1))); + VERIFY_EXPR( AccessFlag != 0 && (AccessFlag & (AccessFlag-1)) == 0 ); + AccessFlags &= ~AccessFlag; + + static constexpr VkPipelineStageFlags ALL_GRAPHICS_SHADER_STAGES_BITS = + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | + VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | + VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | + VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + + // An application MUST NOT specify an access flag in a synchronization command if it does not include a + // pipeline stage in the corresponding stage mask that is able to perform accesses of that type. + // A table that lists, for each access flag, which pipeline stages can perform that type of access is given in 6.1.3. + switch(AccessFlag) + { + // Read access to an indirect command structure read as part of an indirect drawing or dispatch command + case VK_ACCESS_INDIRECT_COMMAND_READ_BIT: + Stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; + break; + + // Read access to an index buffer as part of an indexed drawing command, bound by vkCmdBindIndexBuffer + case VK_ACCESS_INDEX_READ_BIT: + Stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + break; + + // Read access to a vertex buffer as part of a drawing command, bound by vkCmdBindVertexBuffers + case VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: + Stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + break; + + // Read access to a uniform buffer + case VK_ACCESS_UNIFORM_READ_BIT: + Stages |= ALL_GRAPHICS_SHADER_STAGES_BITS | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + break; + + // Read access to an input attachment within a render pass during fragment shading + case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: + Stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + + // Read access to a storage buffer, uniform texel buffer, storage texel buffer, sampled image, or storage image + case VK_ACCESS_SHADER_READ_BIT: + Stages |= ALL_GRAPHICS_SHADER_STAGES_BITS | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + break; + + // Write access to a storage buffer, storage texel buffer, or storage image + case VK_ACCESS_SHADER_WRITE_BIT: + Stages |= ALL_GRAPHICS_SHADER_STAGES_BITS | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + break; + + // Read access to a color attachment, such as via blending, logic operations, or via certain subpass load operations + case VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: + Stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + + // Write access to a color or resolve attachment during a render pass or via certain subpass load and store operations + case VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: + Stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + + // Read access to a depth/stencil attachment, via depth or stencil operations or via certain subpass load operations + case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT: + Stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + + // Write access to a depth/stencil attachment, via depth or stencil operations or via certain subpass load and store operations + case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: + Stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + + // Read access to an image or buffer in a copy operation + case VK_ACCESS_TRANSFER_READ_BIT: + Stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + + // Write access to an image or buffer in a clear or copy operation + case VK_ACCESS_TRANSFER_WRITE_BIT: + Stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + + // Read access by a host operation. Accesses of this type are not performed through a resource, but directly on memory + case VK_ACCESS_HOST_READ_BIT: + Stages |= VK_PIPELINE_STAGE_HOST_BIT; + break; + + // Write access by a host operation. Accesses of this type are not performed through a resource, but directly on memory + case VK_ACCESS_HOST_WRITE_BIT: + Stages |= VK_PIPELINE_STAGE_HOST_BIT; + break; + + // Read access via non-specific entities. When included in a destination access mask, makes all available writes + // visible to all future read accesses on entities known to the Vulkan device + case VK_ACCESS_MEMORY_READ_BIT: + break; + + // Write access via non-specific entities. hen included in a source access mask, all writes that are performed + // by entities known to the Vulkan device are made available. When included in a destination access mask, makes + // all available writes visible to all future write accesses on entities known to the Vulkan device. + case VK_ACCESS_MEMORY_WRITE_BIT: + break; + + default: + UNEXPECTED("Unknown memory access flag"); + } + } + return Stages; +} + +void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer CmdBuffer, + VkImage Image, + VkImageAspectFlags AspectMask, + VkImageLayout OldLayout, + VkImageLayout NewLayout, + const VkImageSubresourceRange& SubresRange, + VkPipelineStageFlags SrcStages, + VkPipelineStageFlags DestStages) +{ + VERIFY_EXPR(CmdBuffer != VK_NULL_HANDLE); + + VkImageMemoryBarrier ImgBarrier = {}; + ImgBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + ImgBarrier.pNext = nullptr; + ImgBarrier.srcAccessMask = 0; + ImgBarrier.dstAccessMask = 0; + ImgBarrier.oldLayout = OldLayout; + ImgBarrier.newLayout = NewLayout; + ImgBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // source queue family for a queue family ownership transfer. + ImgBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // destination queue family for a queue family ownership transfer. + ImgBarrier.image = Image; + ImgBarrier.subresourceRange.aspectMask = AspectMask; + ImgBarrier.subresourceRange = SubresRange; + + switch (OldLayout) + { + // does not support device access. This layout must only be used as the initialLayout member + // of VkImageCreateInfo or VkAttachmentDescription, or as the oldLayout in an image transition. + // When transitioning out of this layout, the contents of the memory are not guaranteed to be preserved (11.4) + case VK_IMAGE_LAYOUT_UNDEFINED: + break; + + // supports all types of device access + case VK_IMAGE_LAYOUT_GENERAL: + UNEXPECTED("General layout is not recommended"); + break; + + // must only be used as a color or resolve attachment in a VkFramebuffer (11.4) + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + ImgBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + break; + + // must only be used as a depth/stencil attachment in a VkFramebuffer (11.4) + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + ImgBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + break; + + // must only be used as a read-only depth/stencil attachment in a VkFramebuffer and/or as a read-only image in a shader (11.4) + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + ImgBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + break; + + // must only be used as a read-only image in a shader (which can be read as a sampled image, + // combined image/sampler and/or input attachment) (11.4) + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + ImgBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + + // must only be used as a source image of a transfer command (11.4) + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + ImgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + break; + + // must only be used as a destination image of a transfer command (11.4) + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + ImgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + + // does not support device access. This layout must only be used as the initialLayout member + // of VkImageCreateInfo or VkAttachmentDescription, or as the oldLayout in an image transition. + // When transitioning out of this layout, the contents of the memory are preserved. (11.4) + case VK_IMAGE_LAYOUT_PREINITIALIZED: + ImgBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: + ImgBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + break; + + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: + ImgBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + break; + + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + ImgBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + break; + + default: + UNEXPECTED("Unexpected image layout"); + break; + } + + + switch (NewLayout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: + UNEXPECTED("The new layout used in a transition must not be VK_IMAGE_LAYOUT_UNDEFINED. " + "This layout must only be used as the initialLayout member of VkImageCreateInfo " + "or VkAttachmentDescription, or as the oldLayout in an image transition. (11.4)"); + break; + + case VK_IMAGE_LAYOUT_GENERAL: + UNEXPECTED("General layout is not recommended due to inefficiency"); + break; + + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + ImgBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + ImgBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + ImgBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + break; + + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + ImgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; + break; + + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + ImgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + break; + + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + ImgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_PREINITIALIZED: + UNEXPECTED("The new layout used in a transition must not be VK_IMAGE_LAYOUT_PREINITIALIZED. " + "This layout must only be used as the initialLayout member of VkImageCreateInfo " + "or VkAttachmentDescription, or as the oldLayout in an image transition. (11.4)"); + break; + + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: + ImgBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + break; + + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: + ImgBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + break; + + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + ImgBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + break; + + default: + UNEXPECTED("Unexpected image layout"); + break; + } + + if(SrcStages == 0) + SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask); + + if (DestStages == 0) + DestStages = PipelineStageFromAccessFlags(ImgBarrier.dstAccessMask); + + vkCmdPipelineBarrier(CmdBuffer, + SrcStages, + DestStages, + 0, // a bitmask specifying how execution and memory dependencies are formed + 0, // memoryBarrierCount + nullptr, // pMemoryBarriers + 0, // bufferMemoryBarrierCount + nullptr, // pBufferMemoryBarriers + 1, + &ImgBarrier); +} + +void VulkanCommandBuffer::FlushBarriers() +{ + +} + +} -- cgit v1.2.3