summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2021-03-19 22:30:07 +0000
committers-ol <s+removethis@s-ol.nu>2021-03-27 08:58:09 +0000
commit8d132768530102638953ffbd3b778920b0336b6a (patch)
tree78b27af3b90246529b3778ff0162cd12b7f37be4 /Graphics/GraphicsEngineVulkan
parentExternal Vulkan Device support (diff)
downloadDiligentCore-8d132768530102638953ffbd3b778920b0336b6a.tar.gz
DiligentCore-8d132768530102638953ffbd3b778920b0336b6a.zip
External Vulkan SwapChain support
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp53
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/EngineFactoryVk.h20
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h10
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h7
-rw-r--r--Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp30
-rw-r--r--Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp791
6 files changed, 102 insertions, 809 deletions
diff --git a/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp
index 94a6d5df..824c9819 100644
--- a/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp
@@ -36,6 +36,7 @@
#include "VulkanUtilities/VulkanInstance.hpp"
#include "VulkanUtilities/VulkanObjectWrappers.hpp"
#include "ManagedVulkanObject.hpp"
+#include "../interface/EngineFactoryVk.h"
namespace Diligent
{
@@ -50,7 +51,9 @@ public:
const SwapChainDesc& SwapChainDesc,
class RenderDeviceVkImpl* pRenderDeviceVk,
class DeviceContextVkImpl* pDeviceContextVk,
- const NativeWindow& Window);
+ uint32_t SwapChainImageCount,
+ const VkImage* pSwapChainImages,
+ SwapChainImageCallbacks SwapChainCallbacks);
~SwapChainVkImpl();
IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_SwapChainVk, TSwapChainBase)
@@ -58,6 +61,12 @@ public:
/// Implementation of ISwapChain::Present() in Vulkan backend.
virtual void DILIGENT_CALL_TYPE Present(Uint32 SyncInterval) override final;
+ /// Implementation of ISwapChain::Present() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE PresentImage() override final;
+
+ /// Implementation of ISwapChainVk::AcquireNextImage() in Vulkan backend.
+ virtual VkResult DILIGENT_CALL_TYPE AcquireNextImage() override final;
+
/// Implementation of ISwapChain::Resize() in Vulkan backend.
virtual void DILIGENT_CALL_TYPE Resize(Uint32 NewWidth, Uint32 NewHeight, SURFACE_TRANSFORM NewPreTransform) override final;
@@ -67,9 +76,6 @@ public:
/// Implementation of ISwapChain::SetWindowedMode() in Vulkan backend.
virtual void DILIGENT_CALL_TYPE SetWindowedMode() override final;
- /// Implementation of ISwapChainVk::GetVkSwapChain().
- virtual VkSwapchainKHR DILIGENT_CALL_TYPE GetVkSwapChain() override final { return m_VkSwapChain; }
-
/// Implementation of ISwapChain::GetCurrentBackBufferRTV() in Vulkan backend.
virtual ITextureViewVk* DILIGENT_CALL_TYPE GetCurrentBackBufferRTV() override final
{
@@ -81,46 +87,19 @@ public:
virtual ITextureViewVk* DILIGENT_CALL_TYPE GetDepthBufferDSV() override final { return m_pDepthBufferDSV; }
private:
- void CreateSurface();
- void CreateVulkanSwapChain();
- void InitBuffersAndViews();
- VkResult AcquireNextImage(DeviceContextVkImpl* pDeviceCtxVk);
- void RecreateVulkanSwapchain(DeviceContextVkImpl* pImmediateCtxVk);
- void WaitForImageAcquiredFences();
- void ReleaseSwapChainResources(DeviceContextVkImpl* pImmediateCtxVk, bool DestroyVkSwapChain);
-
- const NativeWindow m_Window;
+ void InitBuffersAndViews(uint32_t SwapChainImageCount, const VkImage *SwapChainImages);
+ void ReleaseSwapChainResources(DeviceContextVkImpl* pImmediateCtxVk);
std::shared_ptr<const VulkanUtilities::VulkanInstance> m_VulkanInstance;
-
- Uint32 m_DesiredBufferCount = 0;
-
- VkSurfaceKHR m_VkSurface = VK_NULL_HANDLE;
- VkSwapchainKHR m_VkSwapChain = VK_NULL_HANDLE;
- VkFormat m_VkColorFormat = VK_FORMAT_UNDEFINED;
-
-#if PLATFORM_ANDROID
- // Surface extent corresponding to identity transform. We have to store this value,
- // because on Android vkGetPhysicalDeviceSurfaceCapabilitiesKHR is not reliable and
- // starts reporting incorrect dimensions after few rotations.
- VkExtent2D m_SurfaceIdentityExtent = {};
-
- // Keep track of current surface transform to detect orientation changes.
- VkSurfaceTransformFlagBitsKHR m_CurrentSurfaceTransform = VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR;
-#endif
-
- std::vector<RefCntAutoPtr<ManagedSemaphore>> m_ImageAcquiredSemaphores;
- std::vector<RefCntAutoPtr<ManagedSemaphore>> m_DrawCompleteSemaphores;
- std::vector<VulkanUtilities::FenceWrapper> m_ImageAcquiredFences;
-
std::vector<RefCntAutoPtr<ITextureViewVk>, STDAllocatorRawMem<RefCntAutoPtr<ITextureViewVk>>> m_pBackBufferRTV;
-
std::vector<bool, STDAllocatorRawMem<bool>> m_SwapChainImagesInitialized;
- std::vector<bool, STDAllocatorRawMem<bool>> m_ImageAcquiredFenceSubmitted;
RefCntAutoPtr<ITextureViewVk> m_pDepthBufferDSV;
- Uint32 m_SemaphoreIndex = 0;
+ void* m_Cookie;
+ VkResult (*m_AcquireImageCallback)(void* Cookie, uint32_t* Image);
+ void (*m_ReleaseImageCallback)(void* Cookie);
+
uint32_t m_BackBufferIndex = 0;
bool m_IsMinimized = false;
bool m_VSyncEnabled = true;
diff --git a/Graphics/GraphicsEngineVulkan/interface/EngineFactoryVk.h b/Graphics/GraphicsEngineVulkan/interface/EngineFactoryVk.h
index 61210e74..30685ea2 100644
--- a/Graphics/GraphicsEngineVulkan/interface/EngineFactoryVk.h
+++ b/Graphics/GraphicsEngineVulkan/interface/EngineFactoryVk.h
@@ -64,6 +64,14 @@ static const INTERFACE_ID IID_EngineFactoryVk =
// clang-format off
+struct SwapChainImageCallbacks {
+ void* Cookie;
+ VkResult (*ImageCallbackAcquire)(void* Cookie, uint32_t* Image);
+ void (*ImageCallbackRelease)(void* Cookie);
+};
+
+typedef struct SwapChainImageCallbacks SwapChainImageCallbacks;
+
DILIGENT_BEGIN_INTERFACE(IEngineFactoryVk, IEngineFactory)
{
/// Creates a render device and device contexts for Vulkan backend
@@ -101,11 +109,13 @@ DILIGENT_BEGIN_INTERFACE(IEngineFactoryVk, IEngineFactory)
/// \param [out] ppSwapChain - Address of the memory location where pointer to the new
/// swap chain will be written
VIRTUAL void METHOD(CreateSwapChainVk)(THIS_
- IRenderDevice* pDevice,
- IDeviceContext* pImmediateContext,
- const SwapChainDesc REF SwapChainDesc,
- const NativeWindow REF Window,
- ISwapChain** ppSwapChain) PURE;
+ IRenderDevice* pDevice,
+ IDeviceContext* pImmediateContext,
+ const SwapChainDesc REF SwapChainDesc,
+ uint32_t SwapChainImageCount,
+ const VkImage* pSwapChainImages,
+ const SwapChainImageCallbacks REF SwapChainCallbacks,
+ ISwapChain** ppSwapChain) PURE;
};
DILIGENT_END_INTERFACE
diff --git a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h
index 1c0a7efa..e58c7f53 100644
--- a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h
+++ b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h
@@ -31,6 +31,7 @@
/// Definition of the Diligent::IRenderDeviceVk interface
#include "../../GraphicsEngine/interface/RenderDevice.h"
+#include "CommandQueueVk.h"
DILIGENT_BEGIN_NAMESPACE(Diligent)
@@ -150,6 +151,13 @@ DILIGENT_BEGIN_INTERFACE(IRenderDeviceVk, IRenderDevice)
const TopLevelASDesc REF Desc,
RESOURCE_STATE InitialState,
ITopLevelAS** ppTLAS) PURE;
+
+ VIRTUAL ICommandQueueVk* METHOD(LockCommandQueue)(THIS_
+ Uint32 QueueIndex) PURE;
+
+ VIRTUAL void METHOD(UnlockCommandQueue)(THIS_
+ Uint32 QueueIndex) PURE;
+
};
DILIGENT_END_INTERFACE
@@ -169,6 +177,8 @@ DILIGENT_END_INTERFACE
# define IRenderDeviceVk_CreateBufferFromVulkanResource(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateBufferFromVulkanResource, This, __VA_ARGS__)
# define IRenderDeviceVk_CreateBLASFromVulkanResource(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateBLASFromVulkanResource, This, __VA_ARGS__)
# define IRenderDeviceVk_CreateTLASFromVulkanResource(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateTLASFromVulkanResource, This, __VA_ARGS__)
+# define IRenderDeviceVk_LockCommandQueue(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, LockCommandQueue, This, __VA_ARGS__)
+# define IRenderDeviceVk_UnlockCommandQueue(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, UnlockCommandQueue, This, __VA_ARGS__)
// clang-format on
diff --git a/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h b/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h
index 70f327aa..67641935 100644
--- a/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h
+++ b/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h
@@ -49,8 +49,8 @@ static const INTERFACE_ID IID_SwapChainVk =
/// Exposes Vulkan-specific functionality of a swap chain.
DILIGENT_BEGIN_INTERFACE(ISwapChainVk, ISwapChain)
{
- /// Returns a handle to the Vulkan swap chain object.
- VIRTUAL VkSwapchainKHR METHOD(GetVkSwapChain)(THIS) PURE;
+ VIRTUAL void METHOD(PresentImage)(THIS) PURE;
+ VIRTUAL VkResult METHOD(AcquireNextImage)(THIS) PURE;
};
DILIGENT_END_INTERFACE
@@ -60,7 +60,8 @@ DILIGENT_END_INTERFACE
// clang-format off
-# define ISwapChainVk_GetVkSwapChain(This) CALL_IFACE_METHOD(SwapChainVk, GetVkSwapChain, This)
+# define ISwapChainVk_PresentImage(This, ...) CALL_IFACE_METHOD(SwapChainVk, PresentImage, This, __VA_ARGS__)
+# define ISwapChainVk_GetVkBufferView(This) CALL_IFACE_METHOD(SwapChainVk, AcquireNextImage, This)
// clang-format on
diff --git a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp
index b5d06700..376a7a87 100644
--- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp
@@ -84,11 +84,13 @@ public:
IRenderDevice** ppDevice,
IDeviceContext** ppContexts); //override final;
- virtual void DILIGENT_CALL_TYPE CreateSwapChainVk(IRenderDevice* pDevice,
- IDeviceContext* pImmediateContext,
- const SwapChainDesc& SwapChainDesc,
- const NativeWindow& Window,
- ISwapChain** ppSwapChain) override final;
+ virtual void DILIGENT_CALL_TYPE CreateSwapChainVk(IRenderDevice* pDevice,
+ IDeviceContext* pImmediateContext,
+ const SwapChainDesc& SwapChainDesc,
+ uint32_t SwapChainImageCount,
+ const VkImage* pSwapChainImages,
+ const SwapChainImageCallbacks& SwapChainCallbacks,
+ ISwapChain** ppSwapChain) override final;
#if PLATFORM_ANDROID
virtual void InitAndroidFileSystem(struct ANativeActivity* NativeActivity,
@@ -573,8 +575,8 @@ void EngineFactoryVkImpl::AttachToVulkanDevice(const VkInstance& Instanc
};
AttachToVulkanDevice(
- VulkanInstance,
- std::move(VulkanPhysicalDevice),
+ VulkanInstance,
+ std::move(VulkanPhysicalDevice),
VulkanLogicalDevice,
CommandQueues.size(), CommandQueues.data(),
EngineCI,
@@ -669,11 +671,13 @@ void EngineFactoryVkImpl::AttachToVulkanDevice(std::shared_ptr<VulkanUtilities::
}
-void EngineFactoryVkImpl::CreateSwapChainVk(IRenderDevice* pDevice,
- IDeviceContext* pImmediateContext,
- const SwapChainDesc& SCDesc,
- const NativeWindow& Window,
- ISwapChain** ppSwapChain)
+void EngineFactoryVkImpl::CreateSwapChainVk(IRenderDevice* pDevice,
+ IDeviceContext* pImmediateContext,
+ const SwapChainDesc& SCDesc,
+ uint32_t SwapChainImageCount,
+ const VkImage* pSwapChainImages,
+ const SwapChainImageCallbacks& SwapChainCallbacks,
+ ISwapChain** ppSwapChain)
{
VERIFY(ppSwapChain, "Null pointer provided");
if (!ppSwapChain)
@@ -687,7 +691,7 @@ void EngineFactoryVkImpl::CreateSwapChainVk(IRenderDevice* pDevice,
auto* pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pImmediateContext);
auto& RawMemAllocator = GetRawAllocator();
- auto* pSwapChainVk = NEW_RC_OBJ(RawMemAllocator, "SwapChainVkImpl instance", SwapChainVkImpl)(SCDesc, pDeviceVk, pDeviceContextVk, Window);
+ auto* pSwapChainVk = NEW_RC_OBJ(RawMemAllocator, "SwapChainVkImpl instance", SwapChainVkImpl)(SCDesc, pDeviceVk, pDeviceContextVk, SwapChainImageCount, pSwapChainImages, SwapChainCallbacks);
pSwapChainVk->QueryInterface(IID_SwapChain, reinterpret_cast<IObject**>(ppSwapChain));
}
catch (const std::runtime_error&)
diff --git a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp
index 5135067b..6bc3db28 100644
--- a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp
@@ -36,534 +36,42 @@
namespace Diligent
{
-SwapChainVkImpl::SwapChainVkImpl(IReferenceCounters* pRefCounters,
- const SwapChainDesc& SCDesc,
- RenderDeviceVkImpl* pRenderDeviceVk,
- DeviceContextVkImpl* pDeviceContextVk,
- const NativeWindow& Window) :
+SwapChainVkImpl::SwapChainVkImpl(IReferenceCounters* pRefCounters,
+ const SwapChainDesc& SCDesc,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ DeviceContextVkImpl* pDeviceContextVk,
+ uint32_t SwapChainImageCount,
+ const VkImage* pSwapChainImages,
+ SwapChainImageCallbacks SwapChainCallbacks) :
// clang-format off
TSwapChainBase {pRefCounters, pRenderDeviceVk, pDeviceContextVk, SCDesc},
- m_Window {Window},
m_VulkanInstance {pRenderDeviceVk->GetVulkanInstance()},
- m_DesiredBufferCount {SCDesc.BufferCount},
m_pBackBufferRTV (STD_ALLOCATOR_RAW_MEM(RefCntAutoPtr<ITextureView>, GetRawAllocator(), "Allocator for vector<RefCntAutoPtr<ITextureView>>")),
m_SwapChainImagesInitialized (STD_ALLOCATOR_RAW_MEM(bool, GetRawAllocator(), "Allocator for vector<bool>")),
- m_ImageAcquiredFenceSubmitted(STD_ALLOCATOR_RAW_MEM(bool, GetRawAllocator(), "Allocator for vector<bool>"))
+ m_Cookie (SwapChainCallbacks.Cookie),
+ m_AcquireImageCallback (SwapChainCallbacks.ImageCallbackAcquire),
+ m_ReleaseImageCallback (SwapChainCallbacks.ImageCallbackRelease)
// clang-format on
{
- CreateSurface();
- CreateVulkanSwapChain();
- InitBuffersAndViews();
- auto res = AcquireNextImage(pDeviceContextVk);
- DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next image for the newly created swap chain");
- (void)res;
-}
-
-void SwapChainVkImpl::CreateSurface()
-{
- if (m_VkSurface != VK_NULL_HANDLE)
- {
- vkDestroySurfaceKHR(m_VulkanInstance->GetVkInstance(), m_VkSurface, NULL);
- m_VkSurface = VK_NULL_HANDLE;
- }
-
- // Create OS-specific surface
- VkResult err = VK_ERROR_INITIALIZATION_FAILED;
-#if defined(VK_USE_PLATFORM_WIN32_KHR)
- if (m_Window.hWnd != NULL)
- {
- VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {};
-
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
- surfaceCreateInfo.hinstance = GetModuleHandle(NULL);
- surfaceCreateInfo.hwnd = (HWND)m_Window.hWnd;
-
- err = vkCreateWin32SurfaceKHR(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, nullptr, &m_VkSurface);
- }
-#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
- if (m_Window.pAWindow != nullptr)
- {
- VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo = {};
-
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
- surfaceCreateInfo.window = (ANativeWindow*)m_Window.pAWindow;
-
- err = vkCreateAndroidSurfaceKHR(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, NULL, &m_VkSurface);
- }
-#elif defined(VK_USE_PLATFORM_IOS_MVK)
- if (m_Window.pCALayer != nullptr)
- {
- VkIOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
-
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
- surfaceCreateInfo.pView = m_Window.pCALayer;
-
- err = vkCreateIOSSurfaceMVK(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, nullptr, &m_VkSurface);
- }
-#elif defined(VK_USE_PLATFORM_MACOS_MVK)
- if (m_Window.pNSView != nullptr)
- {
- VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
-
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
- surfaceCreateInfo.pView = m_Window.pNSView;
-
- err = vkCreateMacOSSurfaceMVK(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, NULL, &m_VkSurface);
- }
-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
- if (m_Window.pDisplay != nullptr)
- {
- VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = {};
-
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
- surfaceCreateInfo.display = reinterpret_cast<struct wl_display*>(m_Window.pDisplay);
- surfaceCreateInfo.Surface = reinterpret_cast<struct wl_surface*>(nullptr);
-
- err = vkCreateWaylandSurfaceKHR(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, nullptr, &m_VkSurface);
- }
-#elif defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR)
-
-# if defined(VK_USE_PLATFORM_XCB_KHR)
- if (m_Window.pXCBConnection != nullptr && m_Window.WindowId != 0)
- {
- VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = {};
-
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
- surfaceCreateInfo.connection = reinterpret_cast<xcb_connection_t*>(m_Window.pXCBConnection);
- surfaceCreateInfo.window = m_Window.WindowId;
-
- err = vkCreateXcbSurfaceKHR(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, nullptr, &m_VkSurface);
- }
-# endif
-
-# if defined(VK_USE_PLATFORM_XLIB_KHR)
- if ((m_Window.pDisplay != nullptr && m_Window.WindowId != 0) && m_VkSurface == VK_NULL_HANDLE)
- {
- VkXlibSurfaceCreateInfoKHR surfaceCreateInfo = {};
-
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
- surfaceCreateInfo.dpy = reinterpret_cast<Display*>(m_Window.pDisplay);
- surfaceCreateInfo.window = m_Window.WindowId;
-
- err = vkCreateXlibSurfaceKHR(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, nullptr, &m_VkSurface);
- }
-# endif
-
-#endif
-
- CHECK_VK_ERROR_AND_THROW(err, "Failed to create OS-specific surface");
-
- auto* pRenderDeviceVk = m_pRenderDevice.RawPtr<RenderDeviceVkImpl>();
- const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
- auto& CmdQueueVK = pRenderDeviceVk->GetCommandQueue(0);
- auto QueueFamilyIndex = CmdQueueVK.GetQueueFamilyIndex();
- if (!PhysicalDevice.CheckPresentSupport(QueueFamilyIndex, m_VkSurface))
- {
- LOG_ERROR_AND_THROW("Selected physical device does not support present capability.\n"
- "There could be few ways to mitigate this problem. One is to try to find another queue that supports present, but does not support graphics and compute capabilities."
- "Another way is to find another physical device that exposes queue family that supports present and graphics capability. Neither apporach is currently implemented in Diligent Engine.");
- }
-}
-
-void SwapChainVkImpl::CreateVulkanSwapChain()
-{
- auto* pRenderDeviceVk = m_pRenderDevice.RawPtr<RenderDeviceVkImpl>();
- const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
- auto vkDeviceHandle = PhysicalDevice.GetVkDeviceHandle();
- // Get the list of VkFormats that are supported:
- uint32_t formatCount = 0;
-
- auto err = vkGetPhysicalDeviceSurfaceFormatsKHR(vkDeviceHandle, m_VkSurface, &formatCount, NULL);
- CHECK_VK_ERROR_AND_THROW(err, "Failed to query number of supported formats");
- VERIFY_EXPR(formatCount > 0);
- std::vector<VkSurfaceFormatKHR> SupportedFormats(formatCount);
- err = vkGetPhysicalDeviceSurfaceFormatsKHR(vkDeviceHandle, m_VkSurface, &formatCount, SupportedFormats.data());
- CHECK_VK_ERROR_AND_THROW(err, "Failed to query supported format properties");
- VERIFY_EXPR(formatCount == SupportedFormats.size());
- m_VkColorFormat = TexFormatToVkFormat(m_SwapChainDesc.ColorBufferFormat);
-
- VkColorSpaceKHR ColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
- if (formatCount == 1 && SupportedFormats[0].format == VK_FORMAT_UNDEFINED)
- {
- // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
- // the surface has no preferred format. Otherwise, at least one
- // supported format will be returned.
-
- // Do nothing
- }
- else
- {
- bool FmtFound = false;
- for (const auto& SrfFmt : SupportedFormats)
- {
- if (SrfFmt.format == m_VkColorFormat)
- {
- FmtFound = true;
- ColorSpace = SrfFmt.colorSpace;
- break;
- }
- }
- if (!FmtFound)
- {
- VkFormat VkReplacementColorFormat = VK_FORMAT_UNDEFINED;
- switch (m_VkColorFormat)
- {
- // clang-format off
- case VK_FORMAT_R8G8B8A8_UNORM: VkReplacementColorFormat = VK_FORMAT_B8G8R8A8_UNORM; break;
- case VK_FORMAT_B8G8R8A8_UNORM: VkReplacementColorFormat = VK_FORMAT_R8G8B8A8_UNORM; break;
- case VK_FORMAT_B8G8R8A8_SRGB: VkReplacementColorFormat = VK_FORMAT_R8G8B8A8_SRGB; break;
- case VK_FORMAT_R8G8B8A8_SRGB: VkReplacementColorFormat = VK_FORMAT_B8G8R8A8_SRGB; break;
- default: VkReplacementColorFormat = VK_FORMAT_UNDEFINED;
- // clang-format on
- }
-
- bool ReplacementFmtFound = false;
- for (const auto& SrfFmt : SupportedFormats)
- {
- if (SrfFmt.format == VkReplacementColorFormat)
- {
- ReplacementFmtFound = true;
- ColorSpace = SrfFmt.colorSpace;
- break;
- }
- }
-
- if (ReplacementFmtFound)
- {
- m_VkColorFormat = VkReplacementColorFormat;
- auto NewColorBufferFormat = VkFormatToTexFormat(VkReplacementColorFormat);
- LOG_INFO_MESSAGE("Requested color buffer format ", GetTextureFormatAttribs(m_SwapChainDesc.ColorBufferFormat).Name, " is not supported by the surface and will be replaced with ", GetTextureFormatAttribs(NewColorBufferFormat).Name);
- m_SwapChainDesc.ColorBufferFormat = NewColorBufferFormat;
- }
- else
- {
- LOG_WARNING_MESSAGE("Requested color buffer format ", GetTextureFormatAttribs(m_SwapChainDesc.ColorBufferFormat).Name, "is not supported by the surface");
- }
- }
- }
-
- VkSurfaceCapabilitiesKHR surfCapabilities = {};
-
- err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkDeviceHandle, m_VkSurface, &surfCapabilities);
- CHECK_VK_ERROR_AND_THROW(err, "Failed to query physical device surface capabilities");
-
- uint32_t presentModeCount = 0;
-
- err = vkGetPhysicalDeviceSurfacePresentModesKHR(vkDeviceHandle, m_VkSurface, &presentModeCount, NULL);
- CHECK_VK_ERROR_AND_THROW(err, "Failed to query surface present mode count");
- VERIFY_EXPR(presentModeCount > 0);
- std::vector<VkPresentModeKHR> presentModes(presentModeCount);
- err = vkGetPhysicalDeviceSurfacePresentModesKHR(vkDeviceHandle, m_VkSurface, &presentModeCount, presentModes.data());
- CHECK_VK_ERROR_AND_THROW(err, "Failed to query surface present modes");
- VERIFY_EXPR(presentModeCount == presentModes.size());
-
-
- VkSurfaceTransformFlagBitsKHR vkPreTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- if (m_DesiredPreTransform != SURFACE_TRANSFORM_OPTIMAL)
- {
- vkPreTransform = SurfaceTransformToVkSurfaceTransformFlag(m_DesiredPreTransform);
- if ((surfCapabilities.supportedTransforms & vkPreTransform) != 0)
- {
- m_SwapChainDesc.PreTransform = m_DesiredPreTransform;
- }
- else
- {
- LOG_WARNING_MESSAGE(GetSurfaceTransformString(m_DesiredPreTransform),
- " is not supported by the presentation engine. Optimal surface transform will be used instead."
- " Query the swap chain description to get the actual surface transform.");
- m_DesiredPreTransform = SURFACE_TRANSFORM_OPTIMAL;
- }
- }
-
- if (m_DesiredPreTransform == SURFACE_TRANSFORM_OPTIMAL)
- {
- // Use current surface transform to avoid extra cost of presenting the image.
- // If preTransform does not match the currentTransform value returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR,
- // the presentation engine will transform the image content as part of the presentation operation.
- // https://android-developers.googleblog.com/2020/02/handling-device-orientation-efficiently.html
- // https://community.arm.com/developer/tools-software/graphics/b/blog/posts/appropriate-use-of-surface-rotation
- vkPreTransform = surfCapabilities.currentTransform;
- m_SwapChainDesc.PreTransform = VkSurfaceTransformFlagToSurfaceTransform(vkPreTransform);
- LOG_INFO_MESSAGE("Using ", GetSurfaceTransformString(m_SwapChainDesc.PreTransform), " swap chain pretransform");
- }
-
- VkExtent2D swapchainExtent = {};
- // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
- if (surfCapabilities.currentExtent.width == 0xFFFFFFFF && m_SwapChainDesc.Width != 0 && m_SwapChainDesc.Height != 0)
- {
- // If the surface size is undefined, the size is set to
- // the size of the images requested.
- swapchainExtent.width = std::min(std::max(m_SwapChainDesc.Width, surfCapabilities.minImageExtent.width), surfCapabilities.maxImageExtent.width);
- swapchainExtent.height = std::min(std::max(m_SwapChainDesc.Height, surfCapabilities.minImageExtent.height), surfCapabilities.maxImageExtent.height);
- }
- else
- {
- // If the surface size is defined, the swap chain size must match
- swapchainExtent = surfCapabilities.currentExtent;
- }
-
-#if PLATFORM_ANDROID
- // On Android, vkGetPhysicalDeviceSurfaceCapabilitiesKHR is not reliable and starts reporting incorrect
- // dimensions after few rotations. To alleviate the problem, we store the surface extent corresponding to
- // identity rotation.
- // https://android-developers.googleblog.com/2020/02/handling-device-orientation-efficiently.html
- if (m_SurfaceIdentityExtent.width == 0 || m_SurfaceIdentityExtent.height == 0)
- {
- m_SurfaceIdentityExtent = surfCapabilities.currentExtent;
- constexpr auto Rotate90TransformFlags =
- VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
- VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
- VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
- VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
- if ((surfCapabilities.currentTransform & Rotate90TransformFlags) != 0)
- std::swap(m_SurfaceIdentityExtent.width, m_SurfaceIdentityExtent.height);
- }
-
- if (m_DesiredPreTransform == SURFACE_TRANSFORM_OPTIMAL)
- {
- swapchainExtent = m_SurfaceIdentityExtent;
- }
- m_CurrentSurfaceTransform = surfCapabilities.currentTransform;
-#endif
-
- swapchainExtent.width = std::max(swapchainExtent.width, 1u);
- swapchainExtent.height = std::max(swapchainExtent.height, 1u);
- m_SwapChainDesc.Width = swapchainExtent.width;
- m_SwapChainDesc.Height = swapchainExtent.height;
-
- // The FIFO present mode is guaranteed by the spec to always be supported.
- VkPresentModeKHR PresentMode = VK_PRESENT_MODE_FIFO_KHR;
- {
- 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);
- }
-
- 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 (PresentMode)
- {
- PRESENT_MODE_CASE(VK_PRESENT_MODE_IMMEDIATE_KHR)
- PRESENT_MODE_CASE(VK_PRESENT_MODE_MAILBOX_KHR)
- PRESENT_MODE_CASE(VK_PRESENT_MODE_FIFO_KHR)
- PRESENT_MODE_CASE(VK_PRESENT_MODE_FIFO_RELAXED_KHR)
- PRESENT_MODE_CASE(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR)
- PRESENT_MODE_CASE(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR)
- default: PresentModeName = "<UNKNOWN>";
- }
-#undef PRESENT_MODE_CASE
- LOG_INFO_MESSAGE("Using ", PresentModeName, " swap chain present mode");
- }
-
- // Determine the number of VkImage's to use in the swap chain.
- // We need to acquire only 1 presentable image at at time.
- // Asking for minImageCount images ensures that we can acquire
- // 1 presentable image as long as we present it before attempting
- // to acquire another.
- if (m_DesiredBufferCount < surfCapabilities.minImageCount)
- {
- LOG_INFO_MESSAGE("Desired back buffer count (", m_DesiredBufferCount, ") is smaller than the minimal image count supported for this surface (", surfCapabilities.minImageCount, "). Resetting to ", surfCapabilities.minImageCount);
- m_DesiredBufferCount = surfCapabilities.minImageCount;
- }
- if (surfCapabilities.maxImageCount != 0 && m_DesiredBufferCount > surfCapabilities.maxImageCount)
- {
- LOG_INFO_MESSAGE("Desired back buffer count (", m_DesiredBufferCount, ") is greater than the maximal image count supported for this surface (", surfCapabilities.maxImageCount, "). Resetting to ", surfCapabilities.maxImageCount);
- m_DesiredBufferCount = surfCapabilities.maxImageCount;
- }
- // We must use m_DesiredBufferCount instead of m_SwapChainDesc.BufferCount, because Vulkan on Android
- // may decide to always add extra buffers, causing infinite growth of the swap chain when it is recreated:
- // m_SwapChainDesc.BufferCount
- // CreateVulkanSwapChain() 2 -> 4
- // CreateVulkanSwapChain() 4 -> 6
- // CreateVulkanSwapChain() 6 -> 8
- uint32_t desiredNumberOfSwapChainImages = m_DesiredBufferCount;
-
- // Find a supported composite alpha mode - one of these is guaranteed to be set
- VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = //
- {
- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
- VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
- VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
- VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
- };
- for (uint32_t i = 0; i < _countof(compositeAlphaFlags); i++)
- {
- if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i])
- {
- compositeAlpha = compositeAlphaFlags[i];
- break;
- }
- }
-
- auto oldSwapchain = m_VkSwapChain;
- m_VkSwapChain = VK_NULL_HANDLE;
-
- VkSwapchainCreateInfoKHR swapchain_ci = {};
-
- swapchain_ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- swapchain_ci.pNext = NULL;
- swapchain_ci.surface = m_VkSurface;
- swapchain_ci.minImageCount = desiredNumberOfSwapChainImages;
- swapchain_ci.imageFormat = m_VkColorFormat;
- swapchain_ci.imageExtent.width = swapchainExtent.width;
- swapchain_ci.imageExtent.height = swapchainExtent.height;
- swapchain_ci.preTransform = vkPreTransform;
- swapchain_ci.compositeAlpha = compositeAlpha;
- swapchain_ci.imageArrayLayers = 1;
- swapchain_ci.presentMode = PresentMode;
- swapchain_ci.oldSwapchain = oldSwapchain;
- swapchain_ci.clipped = VK_TRUE;
- swapchain_ci.imageColorSpace = ColorSpace;
-
- DEV_CHECK_ERR(m_SwapChainDesc.Usage != 0, "No swap chain usage flags defined");
- static_assert(SWAP_CHAIN_USAGE_LAST == SWAP_CHAIN_USAGE_COPY_SOURCE, "Please update this function to handle the new swapchain usage");
- if (m_SwapChainDesc.Usage & SWAP_CHAIN_USAGE_RENDER_TARGET)
- swapchain_ci.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- if (m_SwapChainDesc.Usage & SWAP_CHAIN_USAGE_SHADER_INPUT)
- swapchain_ci.imageUsage |= VK_IMAGE_USAGE_SAMPLED_BIT;
- if (m_SwapChainDesc.Usage & SWAP_CHAIN_USAGE_COPY_SOURCE)
- swapchain_ci.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_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;
- //uint32_t queueFamilyIndices[] = { (uint32_t)info.graphics_queue_family_index, (uint32_t)info.present_queue_family_index };
- //if (info.graphics_queue_family_index != info.present_queue_family_index) {
- // // If the graphics and present queues are from different queue families,
- // // we either have to explicitly transfer ownership of images between
- // // the queues, or we have to create the swapchain with imageSharingMode
- // // as VK_SHARING_MODE_CONCURRENT
- // swapchain_ci.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
- // swapchain_ci.queueFamilyIndexCount = 2;
- // swapchain_ci.pQueueFamilyIndices = queueFamilyIndices;
- //}
-
- 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(vkDevice, oldSwapchain, NULL);
- oldSwapchain = VK_NULL_HANDLE;
- }
-
- uint32_t swapchainImageCount = 0;
-
- 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)
- {
- LOG_INFO_MESSAGE("Created swap chain with ", swapchainImageCount,
- " images vs ", m_SwapChainDesc.BufferCount, " requested.");
- m_SwapChainDesc.BufferCount = swapchainImageCount;
- }
-
- m_ImageAcquiredSemaphores.resize(swapchainImageCount);
- m_DrawCompleteSemaphores.resize(swapchainImageCount);
- m_ImageAcquiredFences.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
-
- {
- std::stringstream ss;
- ss << "Swap chain image acquired semaphore " << i;
- auto Name = ss.str();
- auto Semaphore = LogicalDevice.CreateSemaphore(SemaphoreCI, Name.c_str());
- ManagedSemaphore::Create(pRenderDeviceVk, std::move(Semaphore), Name.c_str(), &m_ImageAcquiredSemaphores[i]);
- }
-
- {
- std::stringstream ss;
- ss << "Swap chain draw complete semaphore " << i;
- auto Name = ss.str();
- auto Semaphore = LogicalDevice.CreateSemaphore(SemaphoreCI, Name.c_str());
- ManagedSemaphore::Create(pRenderDeviceVk, std::move(Semaphore), Name.c_str(), &m_DrawCompleteSemaphores[i]);
- }
-
- VkFenceCreateInfo FenceCI = {};
-
- FenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- FenceCI.pNext = nullptr;
- FenceCI.flags = 0;
- m_ImageAcquiredFences[i] = LogicalDevice.CreateFence(FenceCI);
- }
+ InitBuffersAndViews(SwapChainImageCount, pSwapChainImages);
}
SwapChainVkImpl::~SwapChainVkImpl()
{
- if (m_VkSwapChain != VK_NULL_HANDLE)
- {
- auto pDeviceContext = m_wpDeviceContext.Lock();
- auto* pImmediateCtxVk = pDeviceContext.RawPtr<DeviceContextVkImpl>();
- ReleaseSwapChainResources(pImmediateCtxVk, /*DestroyVkSwapChain=*/true);
- VERIFY_EXPR(m_VkSwapChain == VK_NULL_HANDLE);
- }
-
- if (m_VkSurface != VK_NULL_HANDLE)
- {
- vkDestroySurfaceKHR(m_VulkanInstance->GetVkInstance(), m_VkSurface, NULL);
- }
+ auto pDeviceContext = m_wpDeviceContext.Lock();
+ auto* pImmediateCtxVk = pDeviceContext.RawPtr<DeviceContextVkImpl>();
+ ReleaseSwapChainResources(pImmediateCtxVk);
}
-void SwapChainVkImpl::InitBuffersAndViews()
+void SwapChainVkImpl::InitBuffersAndViews(uint32_t SwapChainImageCount, const VkImage *pSwapChainImages)
{
auto* pDeviceVkImpl = m_pRenderDevice.RawPtr<RenderDeviceVkImpl>();
auto LogicalVkDevice = pDeviceVkImpl->GetVkDevice();
-#ifdef DILIGENT_DEBUG
- {
- uint32_t swapchainImageCount = 0;
- auto err = vkGetSwapchainImagesKHR(LogicalVkDevice, m_VkSwapChain, &swapchainImageCount, NULL);
- VERIFY_EXPR(err == VK_SUCCESS);
- VERIFY(swapchainImageCount == m_SwapChainDesc.BufferCount, "Unexpected swap chain buffer count");
- }
-#endif
-
m_pBackBufferRTV.resize(m_SwapChainDesc.BufferCount);
m_SwapChainImagesInitialized.resize(m_pBackBufferRTV.size(), false);
- m_ImageAcquiredFenceSubmitted.resize(m_pBackBufferRTV.size(), false);
-
- uint32_t swapchainImageCount = m_SwapChainDesc.BufferCount;
- std::vector<VkImage> swapchainImages(swapchainImageCount);
- auto err = vkGetSwapchainImagesKHR(LogicalVkDevice, m_VkSwapChain, &swapchainImageCount, swapchainImages.data());
- 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;
std::stringstream name_ss;
@@ -578,7 +86,7 @@ void SwapChainVkImpl::InitBuffersAndViews()
BackBufferDesc.MipLevels = 1;
RefCntAutoPtr<TextureVkImpl> pBackBufferTex;
- m_pRenderDevice.RawPtr<RenderDeviceVkImpl>()->CreateTexture(BackBufferDesc, swapchainImages[i], RESOURCE_STATE_UNDEFINED, &pBackBufferTex);
+ m_pRenderDevice.RawPtr<RenderDeviceVkImpl>()->CreateTexture(BackBufferDesc, pSwapChainImages[i], RESOURCE_STATE_UNDEFINED, &pBackBufferTex);
TextureViewDesc RTVDesc;
RTVDesc.ViewType = TEXTURE_VIEW_RENDER_TARGET;
@@ -609,17 +117,18 @@ void SwapChainVkImpl::InitBuffersAndViews()
}
}
-VkResult SwapChainVkImpl::AcquireNextImage(DeviceContextVkImpl* pDeviceCtxVk)
+VkResult SwapChainVkImpl::AcquireNextImage()
{
- auto* pDeviceVk = m_pRenderDevice.RawPtr<RenderDeviceVkImpl>();
- const auto& LogicalDevice = pDeviceVk->GetLogicalDevice();
+ auto pDeviceContext = m_wpDeviceContext.Lock();
+ if (!pDeviceContext)
+ {
+ LOG_ERROR_MESSAGE("Immediate context has been released");
+ return VK_ERROR_UNKNOWN;
+ }
+
+ auto* pDeviceCtxVk = pDeviceContext.RawPtr<DeviceContextVkImpl>();
+ auto* pDeviceVk = m_pRenderDevice.RawPtr<RenderDeviceVkImpl>();
- // Applications should not rely on vkAcquireNextImageKHR blocking in order to
- // meter their rendering speed. The implementation may return from this function
- // immediately regardless of how many presentation requests are queued, and regardless
- // of when queued presentation requests will complete relative to the call. Instead,
- // applications can use fence to meter their frame generation work to match the
- // presentation rate.
// Explicitly make sure that there are no more pending frames in the command queue
// than the number of the swap chain images.
@@ -634,32 +143,16 @@ VkResult SwapChainVkImpl::AcquireNextImage(DeviceContextVkImpl* pDeviceCtxVk)
// When acquiring swap chain image for frame N, we need to make sure that
// frame N-Nsc has completed. To achieve that, we wait for the image acquire
// fence for frame N-Nsc-1. Thus we will have no more than Nsc frames in the queue.
- auto OldestSubmittedImageFenceInd = (m_SemaphoreIndex + 1u) % static_cast<Uint32>(m_ImageAcquiredFenceSubmitted.size());
- if (m_ImageAcquiredFenceSubmitted[OldestSubmittedImageFenceInd])
- {
- VkFence OldestSubmittedFence = m_ImageAcquiredFences[OldestSubmittedImageFenceInd];
- if (LogicalDevice.GetFenceStatus(OldestSubmittedFence) == VK_NOT_READY)
- {
- auto res = LogicalDevice.WaitForFences(1, &OldestSubmittedFence, VK_TRUE, UINT64_MAX);
- VERIFY_EXPR(res == VK_SUCCESS);
- (void)res;
- }
- LogicalDevice.ResetFence(OldestSubmittedFence);
- m_ImageAcquiredFenceSubmitted[OldestSubmittedImageFenceInd] = false;
- }
-
- VkFence ImageAcquiredFence = m_ImageAcquiredFences[m_SemaphoreIndex];
- VkSemaphore ImageAcquiredSemaphore = m_ImageAcquiredSemaphores[m_SemaphoreIndex]->Get();
- auto res = vkAcquireNextImageKHR(LogicalDevice.GetVkDevice(), m_VkSwapChain, UINT64_MAX, ImageAcquiredSemaphore, ImageAcquiredFence, &m_BackBufferIndex);
+ pDeviceVk->LockCommandQueue(0);
+ VkResult res = m_AcquireImageCallback(m_Cookie, &m_BackBufferIndex);
+ pDeviceVk->UnlockCommandQueue(0);
- m_ImageAcquiredFenceSubmitted[m_SemaphoreIndex] = (res == VK_SUCCESS);
if (res == VK_SUCCESS)
{
// Next command in the device context must wait for the next image to be acquired.
// Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore (6.4.2).
// Swapchain image may be used as render target or as destination for copy command.
- pDeviceCtxVk->AddWaitSemaphore(m_ImageAcquiredSemaphores[m_SemaphoreIndex], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT);
if (!m_SwapChainImagesInitialized[m_BackBufferIndex])
{
// Vulkan validation layers do not like uninitialized memory.
@@ -682,6 +175,11 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval)
if (SyncInterval != 0 && SyncInterval != 1)
LOG_WARNING_MESSAGE_ONCE("Vulkan only supports 0 and 1 present intervals");
+ PresentImage();
+}
+
+void SwapChainVkImpl::PresentImage()
+{
auto pDeviceContext = m_wpDeviceContext.Lock();
if (!pDeviceContext)
{
@@ -698,46 +196,18 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval)
if (!m_IsMinimized)
{
// TransitionImageLayout() never triggers flush
- pImmediateCtxVk->TransitionImageLayout(pBackBuffer, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+ pImmediateCtxVk->TransitionImageLayout(pBackBuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// The context can be empty if no render commands were issued by the app
//VERIFY(pImmediateCtxVk->GetNumCommandsInCtx() != 0, "The context must not be flushed");
- pImmediateCtxVk->AddSignalSemaphore(m_DrawCompleteSemaphores[m_SemaphoreIndex]);
}
pImmediateCtxVk->Flush();
if (!m_IsMinimized)
{
- VkPresentInfoKHR PresentInfo = {};
-
- PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
- PresentInfo.pNext = nullptr;
- PresentInfo.waitSemaphoreCount = 1;
- // Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore (6.4.2)
- VkSemaphore WaitSemaphore[] = {m_DrawCompleteSemaphores[m_SemaphoreIndex]->Get()};
- PresentInfo.pWaitSemaphores = WaitSemaphore;
- PresentInfo.swapchainCount = 1;
- PresentInfo.pSwapchains = &m_VkSwapChain;
- PresentInfo.pImageIndices = &m_BackBufferIndex;
- VkResult Result = VK_SUCCESS;
- PresentInfo.pResults = &Result;
- pDeviceVk->LockCmdQueueAndRun(
- 0,
- [&PresentInfo](ICommandQueueVk* pCmdQueueVk) //
- {
- pCmdQueueVk->Present(PresentInfo);
- } //
- );
-
- if (Result == VK_SUBOPTIMAL_KHR || Result == VK_ERROR_OUT_OF_DATE_KHR)
- {
- RecreateVulkanSwapchain(pImmediateCtxVk);
- m_SemaphoreIndex = m_SwapChainDesc.BufferCount - 1; // To start with 0 index when acquire next image
- }
- else
- {
- DEV_CHECK_ERR(Result == VK_SUCCESS, "Present failed");
- }
+ pDeviceVk->LockCommandQueue(0);
+ m_ReleaseImageCallback(m_Cookie);
+ pDeviceVk->UnlockCommandQueue(0);
}
if (m_SwapChainDesc.IsPrimary)
@@ -745,47 +215,10 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval)
pImmediateCtxVk->FinishFrame();
pDeviceVk->ReleaseStaleResources();
}
-
- if (!m_IsMinimized)
- {
- ++m_SemaphoreIndex;
- if (m_SemaphoreIndex >= m_SwapChainDesc.BufferCount)
- m_SemaphoreIndex = 0;
-
- bool EnableVSync = SyncInterval != 0;
-
- auto res = (m_VSyncEnabled == EnableVSync) ? AcquireNextImage(pImmediateCtxVk) : VK_ERROR_OUT_OF_DATE_KHR;
- if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
- {
- m_VSyncEnabled = EnableVSync;
- RecreateVulkanSwapchain(pImmediateCtxVk);
- m_SemaphoreIndex = m_SwapChainDesc.BufferCount - 1; // To start with 0 index when acquire next image
-
- res = AcquireNextImage(pImmediateCtxVk);
- }
- DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next swap chain image");
- }
}
-void SwapChainVkImpl::WaitForImageAcquiredFences()
+void SwapChainVkImpl::ReleaseSwapChainResources(DeviceContextVkImpl* pImmediateCtxVk)
{
- const auto& LogicalDevice = m_pRenderDevice.RawPtr<RenderDeviceVkImpl>()->GetLogicalDevice();
- for (size_t i = 0; i < m_ImageAcquiredFences.size(); ++i)
- {
- if (m_ImageAcquiredFenceSubmitted[i])
- {
- VkFence vkFence = m_ImageAcquiredFences[i];
- if (LogicalDevice.GetFenceStatus(vkFence) == VK_NOT_READY)
- LogicalDevice.WaitForFences(1, &vkFence, VK_TRUE, UINT64_MAX);
- }
- }
-}
-
-void SwapChainVkImpl::ReleaseSwapChainResources(DeviceContextVkImpl* pImmediateCtxVk, bool DestroyVkSwapChain)
-{
- if (m_VkSwapChain == VK_NULL_HANDLE)
- return;
-
if (pImmediateCtxVk != nullptr)
{
// Flush to submit all pending commands and semaphores to the queue.
@@ -810,158 +243,14 @@ void SwapChainVkImpl::ReleaseSwapChainResources(DeviceContextVkImpl* pImmediateC
// m_pBackBufferRTV[].
pDeviceVk->IdleGPU();
- // We need to explicitly wait for all submitted Image Acquired Fences to signal.
- // Just idling the GPU is not enough and results in validation warnings.
- // As a matter of fact, it is only required to check the fence status.
- WaitForImageAcquiredFences();
-
// All references to the swap chain must be released before it can be destroyed
m_pBackBufferRTV.clear();
m_SwapChainImagesInitialized.clear();
- m_ImageAcquiredFenceSubmitted.clear();
m_pDepthBufferDSV.Release();
-
- // We must wait unitl GPU is idled before destroying the fences as they
- // are destroyed immediately. The semaphores are managed and will be kept alive
- // by the device context they are submitted to.
- m_ImageAcquiredSemaphores.clear();
- m_DrawCompleteSemaphores.clear();
- m_ImageAcquiredFences.clear();
- m_SemaphoreIndex = 0;
-
- if (DestroyVkSwapChain)
- {
- vkDestroySwapchainKHR(pDeviceVk->GetVkDevice(), m_VkSwapChain, NULL);
- m_VkSwapChain = VK_NULL_HANDLE;
- }
-}
-
-void SwapChainVkImpl::RecreateVulkanSwapchain(DeviceContextVkImpl* pImmediateCtxVk)
-{
- // Do not destroy Vulkan swap chain as we will use it as oldSwapchain parameter.
- ReleaseSwapChainResources(pImmediateCtxVk, /*DestroyVkSwapChain*/ false);
-
- // Check if the surface is lost
- {
- RenderDeviceVkImpl* pDeviceVk = m_pRenderDevice.RawPtr<RenderDeviceVkImpl>();
- const auto vkDeviceHandle = pDeviceVk->GetPhysicalDevice().GetVkDeviceHandle();
-
- VkSurfaceCapabilitiesKHR surfCapabilities;
- // Call vkGetPhysicalDeviceSurfaceCapabilitiesKHR only to check the return code
- auto err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkDeviceHandle, m_VkSurface, &surfCapabilities);
- if (err == VK_ERROR_SURFACE_LOST_KHR)
- {
- // Destroy the swap chain associated with the surface
- if (m_VkSwapChain != VK_NULL_HANDLE)
- {
- vkDestroySwapchainKHR(pDeviceVk->GetVkDevice(), m_VkSwapChain, NULL);
- m_VkSwapChain = VK_NULL_HANDLE;
- }
-
- // Recreate the surface
- CreateSurface();
- }
- }
-
- CreateVulkanSwapChain();
- InitBuffersAndViews();
}
void SwapChainVkImpl::Resize(Uint32 NewWidth, Uint32 NewHeight, SURFACE_TRANSFORM NewPreTransform)
{
- bool RecreateSwapChain = false;
-
-#if PLATFORM_ANDROID
- if (m_VkSurface != VK_NULL_HANDLE)
- {
- // Check orientation
- const auto* pRenderDeviceVk = m_pRenderDevice.RawPtr<const RenderDeviceVkImpl>();
- const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
- const auto vkDeviceHandle = PhysicalDevice.GetVkDeviceHandle();
-
- VkSurfaceCapabilitiesKHR surfCapabilities = {};
-
- auto err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkDeviceHandle, m_VkSurface, &surfCapabilities);
- if (err == VK_SUCCESS)
- {
- if (m_CurrentSurfaceTransform != surfCapabilities.currentTransform)
- {
- // Surface orientation has changed - we need to recreate the swap chain
- RecreateSwapChain = true;
- }
-
- constexpr auto Rotate90TransformFlags =
- VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
- VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
- VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
- VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
-
- if (NewWidth == 0 || NewHeight == 0)
- {
- NewWidth = m_SurfaceIdentityExtent.width;
- NewHeight = m_SurfaceIdentityExtent.height;
-
- if ((surfCapabilities.currentTransform & Rotate90TransformFlags) != 0)
- {
- // Swap to get logical dimensions as input NewWidth and NewHeight are
- // expected to be logical sizes.
- std::swap(NewWidth, NewHeight);
- }
- }
-
- if (NewPreTransform == SURFACE_TRANSFORM_OPTIMAL)
- {
- if ((surfCapabilities.currentTransform & Rotate90TransformFlags) != 0)
- {
- // Swap to get physical dimensions
- std::swap(NewWidth, NewHeight);
- }
- }
- else
- {
- // Swap if necessary to get desired sizes after pre-transform
- if (NewPreTransform == SURFACE_TRANSFORM_ROTATE_90 ||
- NewPreTransform == SURFACE_TRANSFORM_ROTATE_270 ||
- NewPreTransform == SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90 ||
- NewPreTransform == SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270)
- {
- std::swap(NewWidth, NewHeight);
- }
- }
- }
- else
- {
- LOG_ERROR_MESSAGE(err, "Failed to query physical device surface capabilities");
- }
- }
-#endif
-
- if (TSwapChainBase::Resize(NewWidth, NewHeight, NewPreTransform))
- RecreateSwapChain = true;
-
- if (RecreateSwapChain)
- {
- auto pDeviceContext = m_wpDeviceContext.Lock();
- VERIFY(pDeviceContext, "Immediate context has been released");
- if (pDeviceContext)
- {
- try
- {
- auto* pImmediateCtxVk = pDeviceContext.RawPtr<DeviceContextVkImpl>();
- // RecreateVulkanSwapchain() unbinds default FB
- RecreateVulkanSwapchain(pImmediateCtxVk);
-
- auto res = AcquireNextImage(pImmediateCtxVk);
- DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next image for the just resized swap chain");
- (void)res;
- }
- catch (const std::runtime_error&)
- {
- LOG_ERROR("Failed to resize the swap chain");
- }
- }
- }
-
m_IsMinimized = (NewWidth == 0 && NewHeight == 0);
}