From 38c5e570257e8cd9dcb78ab227baa2a2c877bd0f Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 23 May 2018 13:03:12 +0200 Subject: [PATCH] [dxgi] Refactor Vulkan swap chain and surface creation Creating the Vulkan surface at the latest possible moment fixes an issue with Frostpunk, which renders to a D3D9 swap chain before presenting to the GXGI swap chain. --- src/dxgi/dxgi_presenter.cpp | 75 +++++++++++++++++++++---------------- src/dxgi/dxgi_presenter.h | 34 +++++++---------- src/dxgi/dxgi_swapchain.cpp | 14 +++---- 3 files changed, 62 insertions(+), 61 deletions(-) diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp index 116ea2129..431cca37f 100644 --- a/src/dxgi/dxgi_presenter.cpp +++ b/src/dxgi/dxgi_presenter.cpp @@ -10,15 +10,10 @@ namespace dxvk { DxgiVkPresenter::DxgiVkPresenter( const Rc& device, HWND window) - : m_device (device), + : m_window (window), + m_device (device), m_context (device->createContext()) { - // Create Vulkan surface for the window - HINSTANCE instance = reinterpret_cast( - GetWindowLongPtr(window, GWLP_HINSTANCE)); - - m_surface = m_device->adapter()->createSurface(instance, window); - // Reset options for the swap chain itself. We will // create a swap chain object before presentation. m_options.preferredSurfaceFormat = { VK_FORMAT_UNDEFINED, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; @@ -275,27 +270,52 @@ namespace dxvk { } - void DxgiVkPresenter::RecreateSwapchain(const DxvkSwapchainProperties* pOptions) { + void DxgiVkPresenter::SetGammaControl( + const DXGI_VK_GAMMA_CURVE* pGammaCurve) { + m_context->beginRecording( + m_device->createCommandList()); + + m_context->updateImage(m_gammaTexture, + VkImageSubresourceLayers { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, + VkOffset3D { 0, 0, 0 }, + VkExtent3D { DXGI_VK_GAMMA_CP_COUNT, 1, 1 }, + pGammaCurve, 0, 0); + + m_device->submitCommandList( + m_context->endRecording(), + nullptr, nullptr); + } + + + void DxgiVkPresenter::RecreateSwapchain(DXGI_FORMAT Format, VkPresentModeKHR PresentMode, VkExtent2D WindowSize) { + if (m_surface == nullptr) + m_surface = CreateSurface(); + + DxvkSwapchainProperties options; + options.preferredSurfaceFormat = PickSurfaceFormat(Format); + options.preferredPresentMode = PickPresentMode(PresentMode); + options.preferredBufferSize = WindowSize; + const bool doRecreate = - pOptions->preferredSurfaceFormat.format != m_options.preferredSurfaceFormat.format - || pOptions->preferredSurfaceFormat.colorSpace != m_options.preferredSurfaceFormat.colorSpace - || pOptions->preferredPresentMode != m_options.preferredPresentMode - || pOptions->preferredBufferSize.width != m_options.preferredBufferSize.width - || pOptions->preferredBufferSize.height != m_options.preferredBufferSize.height; + options.preferredSurfaceFormat.format != m_options.preferredSurfaceFormat.format + || options.preferredSurfaceFormat.colorSpace != m_options.preferredSurfaceFormat.colorSpace + || options.preferredPresentMode != m_options.preferredPresentMode + || options.preferredBufferSize.width != m_options.preferredBufferSize.width + || options.preferredBufferSize.height != m_options.preferredBufferSize.height; if (doRecreate) { Logger::info(str::format( "DxgiVkPresenter: Recreating swap chain: ", - "\n Format: ", pOptions->preferredSurfaceFormat.format, - "\n Present mode: ", pOptions->preferredPresentMode, - "\n Buffer size: ", pOptions->preferredBufferSize.width, "x", pOptions->preferredBufferSize.height)); + "\n Format: ", options.preferredSurfaceFormat.format, + "\n Present mode: ", options.preferredPresentMode, + "\n Buffer size: ", options.preferredBufferSize.width, "x", options.preferredBufferSize.height)); if (m_swapchain == nullptr) - m_swapchain = m_device->createSwapchain(m_surface, *pOptions); + m_swapchain = m_device->createSwapchain(m_surface, options); else - m_swapchain->changeProperties(*pOptions); + m_swapchain->changeProperties(options); - m_options = *pOptions; + m_options = options; } } @@ -339,20 +359,11 @@ namespace dxvk { } - void DxgiVkPresenter::SetGammaControl( - const DXGI_VK_GAMMA_CURVE* pGammaCurve) { - m_context->beginRecording( - m_device->createCommandList()); + Rc DxgiVkPresenter::CreateSurface() { + HINSTANCE instance = reinterpret_cast( + GetWindowLongPtr(m_window, GWLP_HINSTANCE)); - m_context->updateImage(m_gammaTexture, - VkImageSubresourceLayers { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, - VkOffset3D { 0, 0, 0 }, - VkExtent3D { DXGI_VK_GAMMA_CP_COUNT, 1, 1 }, - pGammaCurve, 0, 0); - - m_device->submitCommandList( - m_context->endRecording(), - nullptr, nullptr); + return m_device->adapter()->createSurface(instance, m_window); } diff --git a/src/dxgi/dxgi_presenter.h b/src/dxgi/dxgi_presenter.h index 1ce32606e..8709849c0 100644 --- a/src/dxgi/dxgi_presenter.h +++ b/src/dxgi/dxgi_presenter.h @@ -100,28 +100,14 @@ namespace dxvk { * Only actually recreates the swap chain object * if any of the properties have changed. If no * properties have changed, this is a no-op. - * \param [in] options New swap chain options + * \param [in] Format New surface format + * \param [in] PresentMode Present mode + * \param [in] WindowSize Window size */ void RecreateSwapchain( - const DxvkSwapchainProperties* pOptions); - - /** - * \brief Picks a surface format based on a DXGI format - * - * This will return a supported format that, if possible, - * has properties similar to those of the DXGI format. - * \param [in] fmt The DXGI format - * \returns The Vulkan format - */ - VkSurfaceFormatKHR PickSurfaceFormat(DXGI_FORMAT Fmt) const; - - /** - * \brief Picks a supported present mode - * - * \param [in] preferred Preferred present mode - * \returns An actually supported present mode - */ - VkPresentModeKHR PickPresentMode(VkPresentModeKHR Preferred) const; + DXGI_FORMAT Format, + VkPresentModeKHR PresentMode, + VkExtent2D WindowSize); /** * \brief Sets gamma curve @@ -142,6 +128,8 @@ namespace dxvk { GammaTex = 3, }; + HWND m_window; + Rc m_device; Rc m_context; @@ -164,6 +152,12 @@ namespace dxvk { DxvkBlendMode m_blendMode; DxvkSwapchainProperties m_options; + VkSurfaceFormatKHR PickSurfaceFormat(DXGI_FORMAT Fmt) const; + + VkPresentModeKHR PickPresentMode(VkPresentModeKHR Preferred) const; + + Rc CreateSurface(); + Rc CreateSampler( VkFilter Filter, VkSamplerAddressMode AddressMode); diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index ceca91b0e..343cbc044 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -306,15 +306,11 @@ namespace dxvk { // up vertical synchronization properly, but also apply // changes that were made to the window size even if the // Vulkan swap chain itself remains valid. - DxvkSwapchainProperties swapchainProps; - swapchainProps.preferredSurfaceFormat - = m_presenter->PickSurfaceFormat(m_desc.Format); - swapchainProps.preferredPresentMode = SyncInterval == 0 - ? m_presenter->PickPresentMode(VK_PRESENT_MODE_IMMEDIATE_KHR) - : m_presenter->PickPresentMode(VK_PRESENT_MODE_FIFO_KHR); - swapchainProps.preferredBufferSize = GetWindowSize(); - - m_presenter->RecreateSwapchain(&swapchainProps); + VkPresentModeKHR presentMode = SyncInterval == 0 + ? VK_PRESENT_MODE_IMMEDIATE_KHR + : VK_PRESENT_MODE_FIFO_KHR; + + m_presenter->RecreateSwapchain(m_desc.Format, presentMode, GetWindowSize()); m_presenter->PresentImage(); return S_OK; } catch (const DxvkError& err) {