summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2021-02-08 19:56:56 +0000
committerassiduous <assiduous@diligentgraphics.com>2021-03-19 00:31:34 +0000
commit9220e5a6b5e8449786acb996204b140305df94fc (patch)
treeb1977c0108e1f6804ff5e9ba7ebe173a8c09f5e1 /Graphics/GraphicsEngineVulkan
parentReworked PipelineResourceSignatureTest.VulkanDescriptorIndexing to validate r... (diff)
parentUpdated readme (diff)
downloadDiligentCore-9220e5a6b5e8449786acb996204b140305df94fc.tar.gz
DiligentCore-9220e5a6b5e8449786acb996204b140305df94fc.zip
Merged master
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/CMakeLists.txt15
-rw-r--r--Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.hpp10
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp8
-rw-r--r--Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp12
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp85
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp13
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp4
-rw-r--r--Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp44
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp8
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