From 97d54dee1d0007285df88f73a2adc120aa835685 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Thu, 19 Apr 2018 08:45:12 -0700 Subject: Working on vulkan image layout transitions --- .../include/DeviceContextVkImpl.h | 4 +- .../GraphicsEngineVulkan/include/TextureVkImpl.h | 6 +-- .../include/VulkanUtilities/VulkanCommandBuffer.h | 14 ++++-- .../interface/DeviceContextVk.h | 6 +-- .../src/DeviceContextVkImpl.cpp | 35 ++++++++++++-- .../src/RenderDeviceFactoryVk.cpp | 2 + .../src/VulkanUtilities/VulkanCommandBuffer.cpp | 54 ++++++++++++++++++---- 7 files changed, 93 insertions(+), 28 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h index 9652fafa..56ee55f5 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h @@ -86,9 +86,9 @@ public: virtual void ExecuteCommandList(class ICommandList *pCommandList)override final; -#if 0 - virtual void TransitionTextureState(ITexture *pTexture, Vk_RESOURCE_STATES State)override final; + virtual void TransitionImageLayout(ITexture *pTexture, VkImageLayout NewLayout)override final; +#if 0 virtual void TransitionBufferState(IBuffer *pBuffer, Vk_RESOURCE_STATES State)override final; ///// Clears the state caches. This function is called once per frame diff --git a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h index 223ca9bd..7efce04b 100644 --- a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h @@ -68,10 +68,8 @@ public: virtual void Map( IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags, MappedTextureSubresource &MappedData )override; virtual void Unmap( IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags )override; -/* - virtual IVkResource* GetVkTexture(){ return GetVkResource(); } - */ - virtual void* GetNativeHandle()override final { return nullptr;/*GetVkTexture();*/ } + virtual VkImage GetVkImage(){ return m_VulkanImage; } + virtual void* GetNativeHandle()override final { return GetVkImage(); } /* virtual void SetVkResourceState(Vk_RESOURCE_STATES state)override final{ SetState(state); } */ diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h index c2fff6a2..9d800f48 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h @@ -242,7 +242,6 @@ namespace VulkanUtilities static void TransitionImageLayout(VkCommandBuffer CmdBuffer, VkImage Image, - VkImageAspectFlags AspectMask, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange, @@ -250,15 +249,20 @@ namespace VulkanUtilities VkPipelineStageFlags DestStages); void TransitionImageLayout(VkImage Image, - VkImageAspectFlags AspectMask, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange, - VkPipelineStageFlags SrcStages, - VkPipelineStageFlags DestStages) + VkPipelineStageFlags SrcStages = 0, + VkPipelineStageFlags DestStages = 0) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); - TransitionImageLayout(m_VkCmdBuffer, Image, AspectMask, OldLayout, NewLayout, SubresRange, SrcStages, DestStages); + if(m_State.RenderPass != VK_NULL_HANDLE) + { + // Image layout transitions within a render pass execute + // dependencies between attachments + EndRenderPass(); + } + TransitionImageLayout(m_VkCmdBuffer, Image, OldLayout, NewLayout, SubresRange, SrcStages, DestStages); } void FlushBarriers(); diff --git a/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h b/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h index 9a283151..50ec9d75 100644 --- a/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h @@ -40,11 +40,11 @@ class IDeviceContextVk : public IDeviceContext { public: - /// Transitions internal D3D12 texture object to a specified state + /// Transitions internal vulkan image to a specified layout /// \param [in] pTexture - texture to transition - /// \param [in] State - D3D12 resource state this texture to transition to - //virtual void TransitionTextureState(ITexture *pTexture, D3D12_RESOURCE_STATES State) = 0; + /// \param [in] NewLayout - Vulkan image layout this texture to transition to + virtual void TransitionImageLayout(ITexture *pTexture, VkImageLayout NewLayout) = 0; /// Transitions internal D3D12 buffer object to a specified state diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 22200917..42ded191 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -889,14 +889,41 @@ namespace Diligent #endif } -#if 0 - void DeviceContextVkImpl::TransitionTextureState(ITexture *pTexture, Vk_RESOURCE_STATES State) + + void DeviceContextVkImpl::TransitionImageLayout(ITexture *pTexture, VkImageLayout NewLayout) { VERIFY_EXPR(pTexture != nullptr); - auto *pCmdCtx = RequestCmdContext(); - pCmdCtx->TransitionResource(ValidatedCast(pTexture), State); + auto pTextureVk = ValidatedCast(pTexture); + if(pTextureVk->GetLayout() != NewLayout) + { + EnsureVkCmdBuffer(); + + auto vkImg = pTextureVk->GetVkImage(); + const auto& TexDesc = pTextureVk->GetDesc(); + auto Fmt = TexDesc.Format; + const auto& FmtAttribs = GetTextureFormatAttribs(Fmt); + VkImageSubresourceRange SubresRange; + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) + SubresRange.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) + SubresRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + } + 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, pTextureVk->GetLayout(), NewLayout, SubresRange); + pTextureVk->SetLayout(NewLayout); + } } +#if 0 void DeviceContextVkImpl::TransitionBufferState(IBuffer *pBuffer, Vk_RESOURCE_STATES State) { VERIFY_EXPR(pBuffer != nullptr); diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp index 2c2f1bcd..47300c06 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp @@ -155,6 +155,8 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk( const EngineVkAttribs& Crea DeviceFeatures.depthClamp = VK_TRUE; DeviceFeatures.independentBlend = VK_TRUE; DeviceFeatures.samplerAnisotropy = VK_TRUE; + DeviceFeatures.geometryShader = VK_TRUE; + DeviceFeatures.tessellationShader= VK_TRUE; DeviceCreateInfo.pEnabledFeatures = &DeviceFeatures; // NULL or a pointer to a VkPhysicalDeviceFeatures structure that contains // boolean indicators of all the features to be enabled. diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp index 3f5710a2..2f06cdb5 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp @@ -145,7 +145,6 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags AccessFla void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer CmdBuffer, VkImage Image, - VkImageAspectFlags AspectMask, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange, @@ -164,7 +163,6 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer CmdBuffer, 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) @@ -182,12 +180,12 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer CmdBuffer, // 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; + ImgBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | 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; + ImgBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | 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) @@ -249,11 +247,11 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer CmdBuffer, break; case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - ImgBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + ImgBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; break; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - ImgBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + ImgBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; break; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: @@ -296,14 +294,44 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer CmdBuffer, } if(SrcStages == 0) - SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask); + { + if(ImgBarrier.srcAccessMask != 0) + { + SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask); + } + else + { + // An execution dependency with only VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT in the source stage + // mask will effectively not wait for any prior commands to complete. (6.1.2) + SrcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + } + } if (DestStages == 0) - DestStages = PipelineStageFromAccessFlags(ImgBarrier.dstAccessMask); + { + if(ImgBarrier.dstAccessMask != 0) + { + DestStages = PipelineStageFromAccessFlags(ImgBarrier.dstAccessMask); + } + else + { + // An execution dependency with only VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT in the destination + // stage mask will only prevent that stage from executing in subsequently submitted commands. + // As this stage does not perform any actual execution, this is not observable - in effect, + // it does not delay processing of subsequent commands. (6.1.2) + DestStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + } + } + + // Including a particular pipeline stage in the first synchronization scope of a command implicitly + // includes logically earlier pipeline stages in the synchronization scope. Similarly, the second + // synchronization scope includes logically later pipeline stages. + // However, note that access scopes are not affected in this way - only the precise stages specified + // are considered part of each access scope. (6.1.2) vkCmdPipelineBarrier(CmdBuffer, - SrcStages, - DestStages, + SrcStages, // must not be 0 + DestStages, // must not be 0 0, // a bitmask specifying how execution and memory dependencies are formed 0, // memoryBarrierCount nullptr, // pMemoryBarriers @@ -311,6 +339,12 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer CmdBuffer, nullptr, // pBufferMemoryBarriers 1, &ImgBarrier); + // Each element of pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers must not + // have any access flag included in its srcAccessMask member if that bit is not supported by + // any of the pipeline stages in srcStageMask. + // Each element of pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers must not + // have any access flag included in its dstAccessMask member if that bit is not supported by any + // of the pipeline stages in dstStageMask (6.6) } void VulkanCommandBuffer::FlushBarriers() -- cgit v1.2.3