diff options
| author | s-ol <s+removethis@s-ol.nu> | 2021-03-19 22:30:07 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2021-03-27 08:58:09 +0000 |
| commit | 8d132768530102638953ffbd3b778920b0336b6a (patch) | |
| tree | 78b27af3b90246529b3778ff0162cd12b7f37be4 /Graphics/GraphicsEngineVulkan | |
| parent | External Vulkan Device support (diff) | |
| download | DiligentCore-8d132768530102638953ffbd3b778920b0336b6a.tar.gz DiligentCore-8d132768530102638953ffbd3b778920b0336b6a.zip | |
External Vulkan SwapChain support
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
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); } |
