From fadc28867982ec4088fa323d7702ba124a07df35 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Fri, 20 Apr 2018 19:27:11 -0700 Subject: Implemented present in Vulkan swap chain; implemented clear color & depth outside of render pass --- .../include/CommandQueueVkImpl.h | 2 + .../include/DeviceContextVkImpl.h | 14 +++ .../include/RenderDeviceVkImpl.h | 1 + .../GraphicsEngineVulkan/include/SwapChainVkImpl.h | 12 +- .../include/VulkanUtilities/VulkanCommandBuffer.h | 6 + .../include/VulkanUtilities/VulkanObjectWrappers.h | 1 + .../interface/CommandQueueVk.h | 5 + .../GraphicsEngineVulkan/interface/SwapChainVk.h | 14 +-- .../src/CommandQueueVkImpl.cpp | 28 +++-- .../src/DeviceContextVkImpl.cpp | 121 +++++++++++++++++---- .../src/RenderDeviceVkImpl.cpp | 12 +- .../GraphicsEngineVulkan/src/SwapChainVkImpl.cpp | 92 ++++++++++++---- .../src/VulkanUtilities/VulkanCommandBuffer.cpp | 12 +- 13 files changed, 248 insertions(+), 72 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h b/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h index bf8a2866..99db417c 100644 --- a/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h @@ -56,6 +56,8 @@ public: // Executes a given command buffer virtual Uint64 ExecuteCommandBuffer(VkCommandBuffer cmdBuffer)override final; + virtual Uint64 ExecuteCommandBuffer(const VkSubmitInfo& SubmitInfo)override final; + virtual VkQueue GetVkQueue()override final{return m_VkQueue;} virtual uint32_t GetQueueFamilyIndex()override final { return m_QueueFamilyIndex; } diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h index 56ee55f5..82b94413 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h @@ -88,6 +88,16 @@ public: virtual void TransitionImageLayout(ITexture *pTexture, VkImageLayout NewLayout)override final; + void AddWaitSemaphore(VkSemaphore Semaphore, VkPipelineStageFlags WaitDstStageMask) + { + m_WaitSemaphores.push_back(Semaphore); + m_WaitDstStageMasks.push_back(WaitDstStageMask); + } + void AddSignalSemaphore(VkSemaphore Semaphore) + { + m_SignalSemaphores.push_back(Semaphore); + } + #if 0 virtual void TransitionBufferState(IBuffer *pBuffer, Vk_RESOURCE_STATES State)override final; @@ -162,6 +172,10 @@ private: const Uint32 m_ContextId; #endif VulkanUtilities::VulkanCommandBufferPool m_CmdPool; + + std::vector m_WaitSemaphores; + std::vector m_WaitDstStageMasks; + std::vector m_SignalSemaphores; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h index 471ed78c..5751b35b 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h @@ -98,6 +98,7 @@ public: void IdleGPU(bool ReleaseStaleObjects); VkCommandBuffer AllocateCommandBuffer(const Char *DebugName = nullptr); + void ExecuteCommandBuffer(const VkSubmitInfo &SubmitInfo, bool DiscardStaleObjects); void ExecuteCommandBuffer(VkCommandBuffer CmdBuff, bool DiscardStaleObjects); void DisposeCommandBuffer(VkCommandBuffer CmdBuff); diff --git a/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h index e8304c94..d5832b79 100644 --- a/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h @@ -29,6 +29,7 @@ #include "SwapChainVk.h" #include "SwapChainBase.h" #include "VulkanUtilities/VulkanInstance.h" +#include "VulkanUtilities/VulkanObjectWrappers.h" namespace Diligent { @@ -56,23 +57,26 @@ public: virtual void SetWindowedMode()override final; -/* - virtual IDXGISwapChain* GetDXGISwapChain()override final{ return m_pSwapChain; } + virtual VkSwapchainKHR GetVkSwapChain()override final{ return m_VkSwapChain; } virtual ITextureViewVk* GetCurrentBackBufferRTV()override final; virtual ITextureViewVk* GetDepthBufferDSV()override final{return m_pDepthBufferDSV;} - */ + private: void CreateVulkanSwapChain(); void InitBuffersAndViews(); + void AcquireNextImage(DeviceContextVkImpl *pDeviceCtxVk); std::shared_ptr m_VulkanInstance; VkSurfaceKHR m_VkSurface = VK_NULL_HANDLE; VkSwapchainKHR m_VkSwapChain = VK_NULL_HANDLE; VkFormat m_VkColorFormat = VK_FORMAT_UNDEFINED; + std::vector m_ImageAcquiredSemaphores; + std::vector m_DrawCompleteSemaphores; std::vector< RefCntAutoPtr, STDAllocatorRawMem> > m_pBackBufferRTV; RefCntAutoPtr m_pDepthBufferDSV; - + Uint32 m_SemaphoreIndex = 0; + uint32_t m_BackBufferIndex = 0; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h index 9d800f48..90341766 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h @@ -179,6 +179,12 @@ namespace VulkanUtilities m_State.Framebuffer = VK_NULL_HANDLE; } + void EndCommandBuffer() + { + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + vkEndCommandBuffer(m_VkCmdBuffer); + } + void Reset() { m_VkCmdBuffer = VK_NULL_HANDLE; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.h index 783a1e66..5507d94e 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.h @@ -56,6 +56,7 @@ namespace VulkanUtilities } VulkanObjectWrapper& operator = (VulkanObjectWrapper&& rhs) { + Release(); m_pLogicalDevice = std::move(rhs.m_pLogicalDevice); m_VkObject = rhs.m_VkObject; rhs.m_VkObject = VK_NULL_HANDLE; diff --git a/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h b/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h index 9ed10106..ca1a4acc 100644 --- a/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h @@ -48,6 +48,11 @@ public: /// \return Fence value associated with the executed command buffer virtual Uint64 ExecuteCommandBuffer(VkCommandBuffer cmdBuffer) = 0; + /// Submits a given chunk of work to the command queue + + /// \return Fence value associated with the executed command buffer + virtual Uint64 ExecuteCommandBuffer(const VkSubmitInfo& SubmitInfo) = 0; + /// Returns Vulkan command queue. May return VK_NULL_HANDLE if queue is anavailable virtual VkQueue GetVkQueue() = 0; diff --git a/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h b/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h index 77b1a7b2..89294efb 100644 --- a/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h @@ -43,23 +43,17 @@ class ISwapChainVk : public ISwapChain { public: - /// Returns a pointer to the IDXGISwapChain interface of the internal DXGI object. - - /// The method does *NOT* call AddRef() on the returned interface, - /// so Release() must not be called. - //virtual IDXGISwapChain *GetDXGISwapChain() = 0; + /// Returns a handle to the Vulkan swap chain object. + virtual VkSwapchainKHR GetVkSwapChain() = 0; /// Returns a pointer to the render target view of the current back buffer in the swap chain - - /// The method does *NOT* call AddRef() on the returned interface, - /// so Release() must not be called. - //virtual ITextureViewD3D12* GetCurrentBackBufferRTV() = 0; + virtual ITextureViewVk* GetCurrentBackBufferRTV() = 0; /// Returns a pointer to the depth-stencil view of the depth buffer /// The method does *NOT* call AddRef() on the returned interface, /// so Release() must not be called. - //virtual ITextureViewD3D12* GetDepthBufferDSV() = 0; + virtual ITextureViewVk* GetDepthBufferDSV() = 0; }; } diff --git a/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp index b25c412c..99ff89e8 100644 --- a/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp @@ -55,10 +55,24 @@ CommandQueueVkImpl::~CommandQueueVkImpl() IMPLEMENT_QUERY_INTERFACE( CommandQueueVkImpl, IID_CommandQueueVk, TBase ) -Uint64 CommandQueueVkImpl::ExecuteCommandBuffer(VkCommandBuffer cmdBuffer) +Uint64 CommandQueueVkImpl::ExecuteCommandBuffer(const VkSubmitInfo& SubmitInfo) { std::lock_guard Lock(m_QueueMutex); + auto Fence = m_FencePool.GetFence(); + auto err = vkQueueSubmit(m_VkQueue, 1, &SubmitInfo, Fence); + VERIFY(err == VK_SUCCESS, "Failed to submit command buffer to the command queue"); + + // We must atomically place the (value, fence) pair into the deque + auto FenceValue = m_NextFenceValue; + m_PendingFences.emplace_back(FenceValue, std::move(Fence)); + + // Increment the value + Atomics::AtomicIncrement(m_NextFenceValue); + return FenceValue; +} +Uint64 CommandQueueVkImpl::ExecuteCommandBuffer(VkCommandBuffer cmdBuffer) +{ VkSubmitInfo SubmitInfo = {}; SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; SubmitInfo.commandBufferCount = 1; @@ -73,17 +87,7 @@ Uint64 CommandQueueVkImpl::ExecuteCommandBuffer(VkCommandBuffer cmdBuffer) SubmitInfo.pSignalSemaphores = nullptr; // a pointer to an array of semaphores which will be signaled when the // command buffers for this batch have completed execution - auto Fence = m_FencePool.GetFence(); - auto err = vkQueueSubmit(m_VkQueue, 1, &SubmitInfo, Fence); - VERIFY(err == VK_SUCCESS, "Failed to submit command buffer to the command queue"); - - // We must atomically place the (value, fence) pair into the deque - auto FenceValue = m_NextFenceValue; - m_PendingFences.emplace_back(FenceValue, std::move(Fence)); - - // Increment the value - Atomics::AtomicIncrement(m_NextFenceValue); - return FenceValue; + return ExecuteCommandBuffer(SubmitInfo); } void CommandQueueVkImpl::IdleGPU() diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 42ded191..91b058e9 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -492,13 +492,12 @@ namespace Diligent void DeviceContextVkImpl::ClearDepthStencil( ITextureView *pView, Uint32 ClearFlags, float fDepth, Uint8 Stencil ) { -#if 0 - ITextureViewVk *pDSVVk = nullptr; + ITextureViewVk *pVkDSV = nullptr; if( pView != nullptr ) { - pDSVVk = ValidatedCast(pView); + pVkDSV = ValidatedCast(pView); #ifdef _DEBUG - const auto& ViewDesc = pDSVVk->GetDesc(); + const auto& ViewDesc = pVkDSV->GetDesc(); VERIFY( ViewDesc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL, "Incorrect view type: depth stencil is expected" ); #endif } @@ -506,7 +505,7 @@ namespace Diligent { if (m_pSwapChain) { - pDSVVk = m_pSwapChain.RawPtr()->GetDepthBufferDSV(); + pVkDSV = m_pSwapChain.RawPtr()->GetDepthBufferDSV(); } else { @@ -514,19 +513,62 @@ namespace Diligent return; } } - Vk_CLEAR_FLAGS VkClearFlags = (Vk_CLEAR_FLAGS)0; - if( ClearFlags & CLEAR_DEPTH_FLAG ) VkClearFlags |= Vk_CLEAR_FLAG_DEPTH; - if( ClearFlags & CLEAR_STENCIL_FLAG ) VkClearFlags |= Vk_CLEAR_FLAG_STENCIL; - // The full extent of the resource view is always cleared. - // Viewport and scissor settings are not applied?? - RequestCmdContext()->AsGraphicsContext().ClearDepthStencil( pDSVVk, VkClearFlags, fDepth, Stencil ); -#endif + + auto *pTexture = pVkDSV->GetTexture(); + auto *pTextureVk = ValidatedCast(pTexture); + const auto &ViewDesc = pVkDSV->GetDesc(); + EnsureVkCmdBuffer(); + if(m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) + { + UNSUPPORTED("Not yet implemented"); + } + else + { + // 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); + VkClearDepthStencilValue ClearValue; + ClearValue.depth = fDepth; + ClearValue.stencil = Stencil; + VkImageSubresourceRange Subresource; + Subresource.aspectMask = 0; + if (ClearFlags & CLEAR_DEPTH_FLAG) Subresource.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (ClearFlags & CLEAR_STENCIL_FLAG) Subresource.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + Subresource.baseArrayLayer = ViewDesc.FirstArraySlice; + Subresource.layerCount = ViewDesc.NumArraySlices; + Subresource.baseMipLevel = ViewDesc.MostDetailedMip; + Subresource.levelCount = ViewDesc.NumMipLevels; + + m_CommandBuffer.ClearDepthStencilImage(pTextureVk->GetVkImage(), ClearValue, Subresource); + } + ++m_State.NumCommands; } + VkClearColorValue ClearValueToVkClearValue(const float *RGBA, TEXTURE_FORMAT TexFmt) + { + VkClearColorValue ClearValue; + const auto& FmtAttribs = GetTextureFormatAttribs(TexFmt); + if(FmtAttribs.ComponentType == COMPONENT_TYPE_SINT) + { + for(int i=0; i < 4; ++i) + ClearValue.int32[i] = static_cast(RGBA[i]); + } + else if (FmtAttribs.ComponentType == COMPONENT_TYPE_UINT) + { + for (int i = 0; i < 4; ++i) + ClearValue.uint32[i] = static_cast(RGBA[i]); + } + else + { + for (int i = 0; i < 4; ++i) + ClearValue.float32[i] = RGBA[i]; + } + + return ClearValue; + } + void DeviceContextVkImpl::ClearRenderTarget( ITextureView *pView, const float *RGBA ) { -#if 0 ITextureViewVk *pVkRTV = nullptr; if( pView != nullptr ) { @@ -552,11 +594,30 @@ namespace Diligent static constexpr float Zero[4] = { 0.f, 0.f, 0.f, 0.f }; if( RGBA == nullptr ) RGBA = Zero; + + auto *pTexture = pVkRTV->GetTexture(); + auto *pTextureVk = ValidatedCast(pTexture); + const auto &ViewDesc = pVkRTV->GetDesc(); + EnsureVkCmdBuffer(); + if(m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) + { + UNSUPPORTED("Not yet implemented"); + } + else + { + // 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); + auto ClearValue = ClearValueToVkClearValue(RGBA, ViewDesc.Format); + VkImageSubresourceRange Subresource; + Subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + Subresource.baseArrayLayer = ViewDesc.FirstArraySlice; + Subresource.layerCount = ViewDesc.NumArraySlices; + Subresource.baseMipLevel = ViewDesc.MostDetailedMip; + Subresource.levelCount = ViewDesc.NumMipLevels; + + m_CommandBuffer.ClearColorImage(pTextureVk->GetVkImage(), ClearValue, Subresource); + } - // The full extent of the resource view is always cleared. - // Viewport and scissor settings are not applied?? - RequestCmdContext()->AsGraphicsContext().ClearRenderTarget( pVkRTV, RGBA ); -#endif ++m_State.NumCommands; } @@ -571,8 +632,30 @@ namespace Diligent VERIFY(!m_bIsDeferred, "Deferred contexts cannot execute command lists directly"); if (m_State.NumCommands != 0) { - //m_pCurrCmdCtx->FlushResourceBarriers(); - pDeviceVkImpl->ExecuteCommandBuffer(vkCmdBuff, true); + if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) + { + m_CommandBuffer.EndRenderPass(); + } + + m_CommandBuffer.FlushBarriers(); + m_CommandBuffer.EndCommandBuffer(); + + VkSubmitInfo SubmitInfo = {}; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.pNext = nullptr; + SubmitInfo.waitSemaphoreCount = static_cast(m_WaitSemaphores.size()); + VERIFY_EXPR(m_WaitSemaphores.size() == m_WaitDstStageMasks.size()); + SubmitInfo.pWaitSemaphores = SubmitInfo.waitSemaphoreCount != 0 ? m_WaitSemaphores.data() : nullptr; + SubmitInfo.pWaitDstStageMask = SubmitInfo.waitSemaphoreCount != 0 ? m_WaitDstStageMasks.data() : nullptr; + SubmitInfo.commandBufferCount = 1; + SubmitInfo.pCommandBuffers = &vkCmdBuff; + SubmitInfo.signalSemaphoreCount = static_cast(m_SignalSemaphores.size()); + SubmitInfo.pSignalSemaphores = SubmitInfo.signalSemaphoreCount != 0 ? m_SignalSemaphores.data() : nullptr; + pDeviceVkImpl->ExecuteCommandBuffer(SubmitInfo, true); + + m_WaitSemaphores.clear(); + m_WaitDstStageMasks.clear(); + m_SignalSemaphores.clear(); } DisposeVkCmdBuffer(); } diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 0992c17f..6d370ca0 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -129,13 +129,23 @@ void RenderDeviceVkImpl::ExecuteCommandBuffer(VkCommandBuffer CmdBuff, bool Disc auto err = vkEndCommandBuffer(CmdBuff); VERIFY(err == VK_SUCCESS, "Failed to end command buffer"); + VkSubmitInfo SubmitInfo = {}; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.commandBufferCount = 1; + SubmitInfo.pCommandBuffers = &CmdBuff; + ExecuteCommandBuffer(SubmitInfo, DiscardStaleObjects); +} + + +void RenderDeviceVkImpl::ExecuteCommandBuffer(const VkSubmitInfo &SubmitInfo, bool DiscardStaleObjects) +{ Uint64 FenceValue = 0; Uint64 CmdListNumber = 0; { std::lock_guard LockGuard(m_CmdQueueMutex); auto NextFenceValue = m_pCommandQueue->GetNextFenceValue(); // Submit the command list to the queue - FenceValue = m_pCommandQueue->ExecuteCommandBuffer(CmdBuff); + FenceValue = m_pCommandQueue->ExecuteCommandBuffer(SubmitInfo); VERIFY(FenceValue >= NextFenceValue, "Fence value of the executed command list is less than the next fence value previously queried through GetNextFenceValue()"); FenceValue = std::max(FenceValue, NextFenceValue); CmdListNumber = m_NextCmdListNumber; diff --git a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp index 0dfe082b..2b02a874 100644 --- a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp @@ -94,6 +94,7 @@ SwapChainVkImpl::SwapChainVkImpl(IReferenceCounters *pRefCounters, CreateVulkanSwapChain(); InitBuffersAndViews(); + AcquireNextImage(pDeviceContextVk); } void SwapChainVkImpl::CreateVulkanSwapChain() @@ -263,7 +264,9 @@ void SwapChainVkImpl::CreateVulkanSwapChain() swapchain_ci.oldSwapchain = oldSwapchain; swapchain_ci.clipped = VK_TRUE; swapchain_ci.imageColorSpace = ColorSpace; - swapchain_ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + // vkCmdClearColorImage() command requires the image to use VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL layout + // that requires VK_IMAGE_USAGE_TRANSFER_DST_BIT to be set swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_ci.queueFamilyIndexCount = 0; swapchain_ci.pQueueFamilyIndices = NULL; @@ -278,17 +281,18 @@ void SwapChainVkImpl::CreateVulkanSwapChain() // swapchain_ci.pQueueFamilyIndices = queueFamilyIndices; //} - auto LogicalVkDevice = pRenderDeviceVk->GetVkDevice(); - err = vkCreateSwapchainKHR(LogicalVkDevice, &swapchain_ci, NULL, &m_VkSwapChain); + const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); + auto vkDevice = pRenderDeviceVk->GetVkDevice(); + err = vkCreateSwapchainKHR(vkDevice, &swapchain_ci, NULL, &m_VkSwapChain); CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan swapchain"); if(oldSwapchain != VK_NULL_HANDLE) { - vkDestroySwapchainKHR(LogicalVkDevice, oldSwapchain, NULL); + vkDestroySwapchainKHR(vkDevice, oldSwapchain, NULL); } uint32_t swapchainImageCount = 0; - err = vkGetSwapchainImagesKHR(LogicalVkDevice, m_VkSwapChain, &swapchainImageCount, NULL); + err = vkGetSwapchainImagesKHR(vkDevice, m_VkSwapChain, &swapchainImageCount, NULL); CHECK_VK_ERROR_AND_THROW(err, "Failed to request swap chain image count"); VERIFY_EXPR(swapchainImageCount > 0); if (swapchainImageCount != m_SwapChainDesc.BufferCount) @@ -296,6 +300,18 @@ void SwapChainVkImpl::CreateVulkanSwapChain() LOG_INFO_MESSAGE("Actual number of images in the created swap chain: ", m_SwapChainDesc.BufferCount); m_SwapChainDesc.BufferCount = swapchainImageCount; } + + m_ImageAcquiredSemaphores.resize(swapchainImageCount); + m_DrawCompleteSemaphores.resize(swapchainImageCount); + for(uint32_t i = 0; i < swapchainImageCount; ++i) + { + VkSemaphoreCreateInfo SemaphoreCI = {}; + SemaphoreCI.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + SemaphoreCI.pNext = nullptr; + SemaphoreCI.flags = 0; // reserved for future use + m_ImageAcquiredSemaphores[i] = LogicalDevice.CreateSemaphore(SemaphoreCI); + m_DrawCompleteSemaphores[i] = LogicalDevice.CreateSemaphore(SemaphoreCI); + } } SwapChainVkImpl::~SwapChainVkImpl() @@ -329,8 +345,8 @@ void SwapChainVkImpl::InitBuffersAndViews() CHECK_VK_ERROR_AND_THROW(err, "Failed to get swap chain images"); VERIFY_EXPR(swapchainImageCount == swapchainImages.size()); - for (uint32_t i = 0; i < swapchainImageCount; i++) { - + for (uint32_t i = 0; i < swapchainImageCount; i++) + { TextureDesc BackBufferDesc; BackBufferDesc.Format = m_SwapChainDesc.ColorBufferFormat; std::stringstream name_ss; @@ -373,6 +389,18 @@ void SwapChainVkImpl::InitBuffersAndViews() m_pDepthBufferDSV = RefCntAutoPtr(pDSV, IID_TextureViewVk); } +void SwapChainVkImpl::AcquireNextImage(DeviceContextVkImpl *pDeviceCtxVk) +{ + auto *pDeviceVk = m_pRenderDevice.RawPtr(); + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + + auto res = vkAcquireNextImageKHR(LogicalDevice.GetVkDevice(), m_VkSwapChain, UINT64_MAX, m_ImageAcquiredSemaphores[m_SemaphoreIndex], (VkFence)nullptr, &m_BackBufferIndex); + VERIFY(res == VK_SUCCESS, "Failed to acquire next swap chain image"); + + // Next command in the device context must wait for the next image to be acquired + pDeviceCtxVk->AddWaitSemaphore(m_ImageAcquiredSemaphores[m_SemaphoreIndex], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); +} + IMPLEMENT_QUERY_INTERFACE( SwapChainVkImpl, IID_SwapChainVk, TSwapChainBase ) @@ -385,21 +413,30 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval) return; } - auto *pImmediateCtx = pDeviceContext.RawPtr(); - auto *pImmediateCtxVk = ValidatedCast( pImmediateCtx ); + auto *pImmediateCtxVk = pDeviceContext.RawPtr(); -#if 0 - auto *pCmdCtx = pImmediateCtxVk->RequestCmdContext(); - auto *pBackBuffer = ValidatedCast( GetCurrentBackBufferRTV()->GetTexture() ); - pCmdCtx->TransitionResource( pBackBuffer, Vk_RESOURCE_STATE_PRESENT); -#endif + // TransitionImageLayout() never triggers flush + pImmediateCtxVk->TransitionImageLayout(GetCurrentBackBufferRTV()->GetTexture(), VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + VERIFY(pImmediateCtxVk->GetNumCommandsInCtx() != 0, "The context must not be flushed"); + pImmediateCtxVk->AddSignalSemaphore(m_DrawCompleteSemaphores[m_SemaphoreIndex]); pImmediateCtxVk->Flush(); - auto *pDeviceVk = ValidatedCast( pImmediateCtxVk->GetDevice() ); -#if 0 - auto hr = m_pSwapChain->Present( SyncInterval, 0 ); - VERIFY(SUCCEEDED(hr), "Present failed"); -#endif + VkPresentInfoKHR PresentInfo = {}; + PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + PresentInfo.pNext = nullptr; + PresentInfo.waitSemaphoreCount = 1; + VkSemaphore WaitSemaphore[] = { m_DrawCompleteSemaphores[m_SemaphoreIndex] }; + PresentInfo.pWaitSemaphores = WaitSemaphore; + PresentInfo.swapchainCount = 1; + PresentInfo.pSwapchains = &m_VkSwapChain; + PresentInfo.pImageIndices = &m_BackBufferIndex; + VkResult Result = VK_SUCCESS; + PresentInfo.pResults = &Result; + VERIFY(Result == VK_SUCCESS, "Present failed"); + + auto *pDeviceVk = m_pRenderDevice.RawPtr(); + auto vkCmdQueue = pDeviceVk->GetCmdQueue()->GetVkQueue(); + vkQueuePresentKHR(vkCmdQueue, &PresentInfo); pDeviceVk->FinishFrame(); @@ -412,6 +449,11 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval) pImmediateCtxVk->CommitRenderTargets(); #endif #endif + ++m_SemaphoreIndex; + if (m_SemaphoreIndex >= m_SwapChainDesc.BufferCount) + m_SemaphoreIndex = 0; + + AcquireNextImage(pImmediateCtxVk); } void SwapChainVkImpl::Resize( Uint32 NewWidth, Uint32 NewHeight ) @@ -433,6 +475,9 @@ void SwapChainVkImpl::Resize( Uint32 NewWidth, Uint32 NewHeight ) // All references to the swap chain must be released before it can be resized m_pBackBufferRTV.clear(); m_pDepthBufferDSV.Release(); + m_ImageAcquiredSemaphores.clear(); + m_DrawCompleteSemaphores.clear(); + m_SemaphoreIndex = 0; // This will release references to Vk swap chain buffers hold by // m_pBackBufferRTV[] @@ -440,6 +485,7 @@ void SwapChainVkImpl::Resize( Uint32 NewWidth, Uint32 NewHeight ) CreateVulkanSwapChain(); InitBuffersAndViews(); + AcquireNextImage(pImmediateCtxVk); if( bIsDefaultFBBound ) { @@ -456,14 +502,12 @@ void SwapChainVkImpl::Resize( Uint32 NewWidth, Uint32 NewHeight ) } } -#if 0 ITextureViewVk *SwapChainVkImpl::GetCurrentBackBufferRTV() { - auto CurrentBackBufferIndex = m_pSwapChain->GetCurrentBackBufferIndex(); - VERIFY_EXPR(CurrentBackBufferIndex >= 0 && CurrentBackBufferIndex < m_SwapChainDesc.BufferCount); - return m_pBackBufferRTV[CurrentBackBufferIndex]; + VERIFY_EXPR(m_BackBufferIndex >= 0 && m_BackBufferIndex < m_SwapChainDesc.BufferCount); + return m_pBackBufferRTV[m_BackBufferIndex]; } -#endif + void SwapChainVkImpl::SetFullscreenMode(const DisplayModeAttribs &DisplayMode) { diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp index 2f06cdb5..a4c996a6 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp @@ -295,7 +295,11 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer CmdBuffer, if(SrcStages == 0) { - if(ImgBarrier.srcAccessMask != 0) + if(OldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) + { + SrcStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + } + else if(ImgBarrier.srcAccessMask != 0) { SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask); } @@ -309,7 +313,11 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer CmdBuffer, if (DestStages == 0) { - if(ImgBarrier.dstAccessMask != 0) + if(NewLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) + { + DestStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + } + else if(ImgBarrier.dstAccessMask != 0) { DestStages = PipelineStageFromAccessFlags(ImgBarrier.dstAccessMask); } -- cgit v1.2.3