diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2021-02-08 19:56:56 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2021-03-19 00:31:34 +0000 |
| commit | 9220e5a6b5e8449786acb996204b140305df94fc (patch) | |
| tree | b1977c0108e1f6804ff5e9ba7ebe173a8c09f5e1 /Graphics/GraphicsEngineVulkan | |
| parent | Reworked PipelineResourceSignatureTest.VulkanDescriptorIndexing to validate r... (diff) | |
| parent | Updated readme (diff) | |
| download | DiligentCore-9220e5a6b5e8449786acb996204b140305df94fc.tar.gz DiligentCore-9220e5a6b5e8449786acb996204b140305df94fc.zip | |
Merged master
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
9 files changed, 133 insertions, 66 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index 79e61acd..ff540add 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -266,12 +266,15 @@ if(PLATFORM_WIN32) elseif(PLATFORM_MACOS) # Use Volk elseif(PLATFORM_IOS) - # For the apparent lack of a better way, link with both arm64 and x64 libraries. - # The linker will issue a warning, but this will work for both device and the simulator. - list(APPEND PRIVATE_DEPENDENCIES - "${MoltenVK_FRAMEWORK}/ios-arm64/libMoltenVK.a" - "${MoltenVK_FRAMEWORK}/ios-x86_64-simulator/libMoltenVK.a" - ) + if(CMAKE_OSX_SYSROOT STREQUAL "iphonesimulator" OR PLATFORM_IOS_SIMULATOR) + list(APPEND PRIVATE_DEPENDENCIES + "${MoltenVK_FRAMEWORK}/ios-arm64_x86_64-simulator/libMoltenVK.a" + ) + else() + list(APPEND PRIVATE_DEPENDENCIES + "${MoltenVK_FRAMEWORK}/ios-arm64/libMoltenVK.a" + ) + endif() find_library(CORE_GRAPHICS CoreGraphics) find_library(METAL_LIBRARY Metal) diff --git a/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.hpp index 3b363e30..63707812 100644 --- a/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.hpp @@ -60,12 +60,12 @@ public: VERIFY(m_vkCmdBuff == VK_NULL_HANDLE && !m_pDeferredCtx, "Destroying command list that was never executed"); } - void Close(VkCommandBuffer& CmdBuff, - RefCntAutoPtr<IDeviceContext>& pDeferredCtx) + VkCommandBuffer Close(RefCntAutoPtr<IDeviceContext>& pDeferredCtx) { - CmdBuff = m_vkCmdBuff; - m_vkCmdBuff = VK_NULL_HANDLE; - pDeferredCtx = std::move(m_pDeferredCtx); + auto vkCmdBuff = m_vkCmdBuff; + m_vkCmdBuff = VK_NULL_HANDLE; + pDeferredCtx = std::move(m_pDeferredCtx); + return vkCmdBuff; } private: diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp index 88ebd252..eb298fb1 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -236,8 +236,9 @@ public: /// Implementation of IDeviceContext::FinishCommandList() in Vulkan backend. virtual void DILIGENT_CALL_TYPE FinishCommandList(class ICommandList** ppCommandList) override final; - /// Implementation of IDeviceContext::ExecuteCommandList() in Vulkan backend. - virtual void DILIGENT_CALL_TYPE ExecuteCommandList(class ICommandList* pCommandList) override final; + /// Implementation of IDeviceContext::ExecuteCommandLists() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) override final; /// Implementation of IDeviceContext::SignalFence() in Vulkan backend. virtual void DILIGENT_CALL_TYPE SignalFence(IFence* pFence, Uint64 Value) override final; @@ -400,6 +401,9 @@ private: void CommitViewports(); void CommitScissorRects(); + void Flush(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists); + __forceinline void TransitionOrVerifyBufferState(BufferVkImpl& Buffer, RESOURCE_STATE_TRANSITION_MODE TransitionMode, RESOURCE_STATE RequiredState, diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index 126bff8c..3c5abb22 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp @@ -239,12 +239,18 @@ private: virtual void TestTextureFormat(TEXTURE_FORMAT TexFormat) override final; - // Submits command buffer for execution to the command queue - // Returns the submitted command buffer number and the fence value + // Submits command buffer(s) for execution to the command queue and + // returns the submitted command buffer(s) number and the fence value. + // If SubmitInfo contains multiple command buffers, they all are treated + // like one and sumbitted atomically. // Parameters: // * SubmittedCmdBuffNumber - submitted command buffer number // * SubmittedFenceValue - fence value associated with the submitted command buffer - void SubmitCommandBuffer(Uint32 QueueIndex, const VkSubmitInfo& SubmitInfo, Uint64& SubmittedCmdBuffNumber, Uint64& SubmittedFenceValue, std::vector<std::pair<Uint64, RefCntAutoPtr<IFence>>>* pFences); + void SubmitCommandBuffer(Uint32 QueueIndex, + const VkSubmitInfo& SubmitInfo, + Uint64& SubmittedCmdBuffNumber, + Uint64& SubmittedFenceValue, + std::vector<std::pair<Uint64, RefCntAutoPtr<IFence>>>* pFences); std::shared_ptr<VulkanUtilities::VulkanInstance> m_VulkanInstance; std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> m_PhysicalDevice; diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index fe8786ff..2ae180e7 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -26,7 +26,10 @@ */ #include "pch.h" + #include <sstream> +#include <vector> + #include "RenderDeviceVkImpl.hpp" #include "DeviceContextVkImpl.hpp" #include "PipelineStateVkImpl.hpp" @@ -1235,6 +1238,12 @@ void DeviceContextVkImpl::FinishFrame() void DeviceContextVkImpl::Flush() { + Flush(0, nullptr); +} + +void DeviceContextVkImpl::Flush(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) +{ if (m_bIsDeferred) { LOG_ERROR_MESSAGE("Flush() should only be called for immediate contexts."); @@ -1252,10 +1261,11 @@ void DeviceContextVkImpl::Flush() LOG_ERROR_MESSAGE("Flushing device context inside an active render pass."); } - VkSubmitInfo SubmitInfo = {}; - - SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - SubmitInfo.pNext = nullptr; + // TODO: replace with small_vector + std::vector<VkCommandBuffer> vkCmdBuffs; + std::vector<RefCntAutoPtr<IDeviceContext>> DeferredCtxs; + vkCmdBuffs.reserve(NumCommandLists + 1); + DeferredCtxs.reserve(NumCommandLists + 1); auto vkCmdBuff = m_CommandBuffer.GetVkCmdBuffer(); if (vkCmdBuff != VK_NULL_HANDLE) @@ -1275,14 +1285,32 @@ void DeviceContextVkImpl::Flush() m_CommandBuffer.FlushBarriers(); m_CommandBuffer.EndCommandBuffer(); - SubmitInfo.commandBufferCount = 1; - SubmitInfo.pCommandBuffers = &vkCmdBuff; + vkCmdBuffs.push_back(vkCmdBuff); } } + // Add command buffers from deferred contexts + for (Uint32 i = 0; i < NumCommandLists; ++i) + { + auto* pCmdListVk = ValidatedCast<CommandListVkImpl>(ppCommandLists[i]); + DEV_CHECK_ERR(pCmdListVk != nullptr, "Command list must not be null"); + RefCntAutoPtr<IDeviceContext> pDeferredCtx; + vkCmdBuffs.emplace_back(pCmdListVk->Close(pDeferredCtx)); + VERIFY(vkCmdBuffs.back() != VK_NULL_HANDLE, "Trying to execute empty command buffer"); + VERIFY_EXPR(pDeferredCtx); + DeferredCtxs.emplace_back(std::move(pDeferredCtx)); + } + VERIFY_EXPR(m_VkWaitSemaphores.size() == m_WaitSemaphores.size()); VERIFY_EXPR(m_VkSignalSemaphores.size() == m_SignalSemaphores.size()); + VkSubmitInfo SubmitInfo = {}; + + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.pNext = nullptr; + + SubmitInfo.commandBufferCount = static_cast<uint32_t>(vkCmdBuffs.size()); + SubmitInfo.pCommandBuffers = vkCmdBuffs.data(); SubmitInfo.waitSemaphoreCount = static_cast<uint32_t>(m_WaitSemaphores.size()); VERIFY_EXPR(m_WaitSemaphores.size() == m_WaitDstStageMasks.size()); SubmitInfo.pWaitSemaphores = SubmitInfo.waitSemaphoreCount != 0 ? m_VkWaitSemaphores.data() : nullptr; @@ -1301,11 +1329,25 @@ void DeviceContextVkImpl::Flush() m_VkSignalSemaphores.clear(); m_PendingFences.clear(); + size_t buff_idx = 0; if (vkCmdBuff != VK_NULL_HANDLE) { + VERIFY_EXPR(vkCmdBuffs[buff_idx] == vkCmdBuff); DisposeCurrentCmdBuffer(m_CommandQueueId, SubmittedFenceValue); + ++buff_idx; } + for (Uint32 i = 0; i < NumCommandLists; ++i, ++buff_idx) + { + auto pDeferredCtxVkImpl = DeferredCtxs[i].RawPtr<DeviceContextVkImpl>(); + // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context + pDeferredCtxVkImpl->m_SubmittedBuffersCmdQueueMask.fetch_or(Uint64{1} << m_CommandQueueId); + // It is OK to dispose command buffer from another thread. We are not going to + // record any commands and only need to add the buffer to the queue + pDeferredCtxVkImpl->DisposeVkCmdBuffer(m_CommandQueueId, std::move(vkCmdBuffs[buff_idx]), SubmittedFenceValue); + } + VERIFY_EXPR(buff_idx == vkCmdBuffs.size()); + for (auto& BindInfo : m_DescrSetBindInfo) BindInfo = DescriptorSetBindInfo{}; @@ -2378,7 +2420,8 @@ void DeviceContextVkImpl::FinishCommandList(class ICommandList** ppCommandList) InvalidateState(); } -void DeviceContextVkImpl::ExecuteCommandList(class ICommandList* pCommandList) +void DeviceContextVkImpl::ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) { if (m_bIsDeferred) { @@ -2386,31 +2429,13 @@ void DeviceContextVkImpl::ExecuteCommandList(class ICommandList* pCommandList) return; } - Flush(); - - InvalidateState(); - - CommandListVkImpl* pCmdListVk = ValidatedCast<CommandListVkImpl>(pCommandList); - VkCommandBuffer vkCmdBuff = VK_NULL_HANDLE; + if (NumCommandLists == 0) + return; + DEV_CHECK_ERR(ppCommandLists != nullptr, "ppCommandLists must not be null when NumCommandLists is not zero"); - RefCntAutoPtr<IDeviceContext> pDeferredCtx; - pCmdListVk->Close(vkCmdBuff, pDeferredCtx); - VERIFY(vkCmdBuff != VK_NULL_HANDLE, "Trying to execute empty command buffer"); - VERIFY_EXPR(pDeferredCtx); - VkSubmitInfo SubmitInfo = {}; + Flush(NumCommandLists, ppCommandLists); - SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - SubmitInfo.pNext = nullptr; - SubmitInfo.commandBufferCount = 1; - SubmitInfo.pCommandBuffers = &vkCmdBuff; - VERIFY_EXPR(m_PendingFences.empty()); - auto pDeferredCtxVkImpl = pDeferredCtx.RawPtr<DeviceContextVkImpl>(); - auto SubmittedFenceValue = m_pDevice->ExecuteCommandBuffer(m_CommandQueueId, SubmitInfo, this, nullptr); - // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context - pDeferredCtxVkImpl->m_SubmittedBuffersCmdQueueMask |= Uint64{1} << m_CommandQueueId; - // It is OK to dispose command buffer from another thread. We are not going to - // record any commands and only need to add the buffer to the queue - pDeferredCtxVkImpl->DisposeVkCmdBuffer(m_CommandQueueId, vkCmdBuff, SubmittedFenceValue); + InvalidateState(); } void DeviceContextVkImpl::SignalFence(IFence* pFence, Uint64 Value) diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 8d884c85..f54c8e27 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -45,6 +45,18 @@ namespace Diligent { + +#if !DILIGENT_NO_HLSL +namespace GLSLangUtils +{ +void SpvOptimizerMessageConsumer( + spv_message_level_t level, + const char* /* source */, + const spv_position_t& /* position */, + const char* message); +} +#endif + namespace { @@ -63,6 +75,7 @@ bool StripReflection(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, Target = SPV_ENV_VULKAN_1_1_SPIRV_1_4; spvtools::Optimizer SpirvOptimizer(Target); + SpirvOptimizer.SetMessageConsumer(GLSLangUtils::SpvOptimizerMessageConsumer); // Decorations defined in SPV_GOOGLE_hlsl_functionality1 are the only instructions // removed by strip-reflect-info pass. SPIRV offsets become INVALID after this operation. SpirvOptimizer.RegisterPass(spvtools::CreateStripReflectInfoPass()); diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index bd956877..cc255fba 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -401,7 +401,7 @@ void RenderDeviceVkImpl::SubmitCommandBuffer(Uint32 ) { // Submit the command list to the queue - auto CmbBuffInfo = TRenderDeviceBase::SubmitCommandBuffer(QueueIndex, SubmitInfo, true); + auto CmbBuffInfo = TRenderDeviceBase::SubmitCommandBuffer(QueueIndex, true, SubmitInfo); SubmittedFenceValue = CmbBuffInfo.FenceValue; SubmittedCmdBuffNumber = CmbBuffInfo.CmdBufferNumber; if (pFences != nullptr) @@ -445,7 +445,7 @@ void RenderDeviceVkImpl::FlushStaleResources(Uint32 CmdQueueIndex) // Submit empty command buffer to the queue. This will effectively signal the fence and // discard all resources VkSubmitInfo DummySumbitInfo = {}; - TRenderDeviceBase::SubmitCommandBuffer(0, DummySumbitInfo, true); + TRenderDeviceBase::SubmitCommandBuffer(0, true, DummySumbitInfo); } void RenderDeviceVkImpl::ReleaseStaleResources(bool ForceRelease) diff --git a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp index ee266edc..bd7c0d55 100644 --- a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp @@ -331,19 +331,39 @@ void SwapChainVkImpl::CreateVulkanSwapChain() m_SwapChainDesc.Width = swapchainExtent.width; m_SwapChainDesc.Height = swapchainExtent.height; - // Mailbox is the lowest latency non-tearing presentation mode. - VkPresentModeKHR swapchainPresentMode = m_VSyncEnabled ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_MAILBOX_KHR; - - bool PresentModeSupported = std::find(presentModes.begin(), presentModes.end(), swapchainPresentMode) != presentModes.end(); - if (!PresentModeSupported) + // The FIFO present mode is guaranteed by the spec to always be supported. + VkPresentModeKHR PresentMode = VK_PRESENT_MODE_FIFO_KHR; { - VERIFY(swapchainPresentMode != VK_PRESENT_MODE_FIFO_KHR, "The FIFO present mode is guaranteed by the spec to be supported"); + std::vector<VkPresentModeKHR> PreferredPresentModes; + if (m_VSyncEnabled) + { + // FIFO relaxed waits for the next VSync, but if the frame is late, + // it still shows it even if VSync has already passed, which may + // result in tearing. + PreferredPresentModes.push_back(VK_PRESENT_MODE_FIFO_RELAXED_KHR); + PreferredPresentModes.push_back(VK_PRESENT_MODE_FIFO_KHR); + } + else + { + // Mailbox is the lowest latency non-tearing presentation mode. + PreferredPresentModes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); + PreferredPresentModes.push_back(VK_PRESENT_MODE_IMMEDIATE_KHR); + PreferredPresentModes.push_back(VK_PRESENT_MODE_FIFO_KHR); + } - const char* PresentModeName = nullptr; + for (auto PreferredMode : PreferredPresentModes) + { + if (std::find(presentModes.begin(), presentModes.end(), PreferredMode) != presentModes.end()) + { + PresentMode = PreferredMode; + break; + } + } + const char* PresentModeName = nullptr; #define PRESENT_MODE_CASE(Mode) \ case Mode: PresentModeName = #Mode; break; - switch (swapchainPresentMode) + switch (PresentMode) { PRESENT_MODE_CASE(VK_PRESENT_MODE_IMMEDIATE_KHR) PRESENT_MODE_CASE(VK_PRESENT_MODE_MAILBOX_KHR) @@ -354,11 +374,7 @@ void SwapChainVkImpl::CreateVulkanSwapChain() default: PresentModeName = "<UNKNOWN>"; } #undef PRESENT_MODE_CASE - LOG_WARNING_MESSAGE(PresentModeName, " is not supported. Defaulting to VK_PRESENT_MODE_FIFO_KHR"); - - swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; - // The FIFO present mode is guaranteed by the spec to be supported - VERIFY(std::find(presentModes.begin(), presentModes.end(), swapchainPresentMode) != presentModes.end(), "FIFO present mode must be supported"); + LOG_INFO_MESSAGE("Using ", PresentModeName, " swap chain present mode"); } // Determine the number of VkImage's to use in the swap chain. @@ -417,7 +433,7 @@ void SwapChainVkImpl::CreateVulkanSwapChain() swapchain_ci.preTransform = vkPreTransform; swapchain_ci.compositeAlpha = compositeAlpha; swapchain_ci.imageArrayLayers = 1; - swapchain_ci.presentMode = swapchainPresentMode; + swapchain_ci.presentMode = PresentMode; swapchain_ci.oldSwapchain = oldSwapchain; swapchain_ci.clipped = VK_TRUE; swapchain_ci.imageColorSpace = ColorSpace; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp index b0d72e70..b646a2ed 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp @@ -152,12 +152,12 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags } -static VkPipelineStageFlags AccessMaskFromImageLayout(VkImageLayout Layout, - bool IsDstMask // false - source mask - // true - destination mask +static VkAccessFlags AccessMaskFromImageLayout(VkImageLayout Layout, + bool IsDstMask // false - source mask + // true - destination mask ) { - VkPipelineStageFlags AccessMask = 0; + VkAccessFlags AccessMask = 0; switch (Layout) { // does not support device access. This layout must only be used as the initialLayout member |
