diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 6d3580a54..6599a7e40 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -2,6 +2,7 @@ #include #include "../dxgi/dxgi_monitor.h" +#include "../dxgi/dxgi_surface.h" #include "../dxgi/dxgi_swapchain.h" #include "../dxvk/dxvk_adapter.h" @@ -3002,8 +3003,12 @@ namespace dxvk { InitReturnPtr(ppSwapChain); try { + auto vki = m_device->GetDXVKDevice()->adapter()->vki(); + + Com surfaceFactory = new DxgiSurfaceFactory(vki->getLoaderProc(), hWnd); + Com presenter = new D3D11SwapChain( - m_container, m_device, hWnd, pDesc); + m_container, m_device, surfaceFactory.ptr(), pDesc); *ppSwapChain = presenter.ref(); return S_OK; @@ -3074,9 +3079,14 @@ namespace dxvk { } try { + auto vki = m_device->GetDXVKDevice()->adapter()->vki(); + + // Create surface factory for the window + Com surfaceFactory = new DxgiSurfaceFactory(vki->getLoaderProc(), hWnd); + // Create presenter for the device Com presenter = new D3D11SwapChain( - m_container, m_device, hWnd, &desc); + m_container, m_device, surfaceFactory.ptr(), &desc); // Create the actual swap chain *ppSwapChain = ref(new DxgiSwapChain( diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index 988013d03..a43c6bad2 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -16,23 +16,23 @@ namespace dxvk { D3D11SwapChain::D3D11SwapChain( D3D11DXGIDevice* pContainer, D3D11Device* pDevice, - HWND hWnd, + IDXGIVkSurfaceFactory* pSurfaceFactory, const DXGI_SWAP_CHAIN_DESC1* pDesc) : m_dxgiDevice(pContainer), - m_parent (pDevice), - m_window (hWnd), - m_desc (*pDesc), - m_device (pDevice->GetDXVKDevice()), - m_context (m_device->createContext(DxvkContextType::Supplementary)), + m_parent(pDevice), + m_surfaceFactory(pSurfaceFactory), + m_desc(*pDesc), + m_device(pDevice->GetDXVKDevice()), + m_context(m_device->createContext(DxvkContextType::Supplementary)), m_frameLatencyCap(pDevice->GetOptions()->maxFrameLatency) { CreateFrameLatencyEvent(); - - if (!pDevice->GetOptions()->deferSurfaceCreation) - CreatePresenter(); - + CreatePresenter(); CreateBackBuffer(); CreateBlitter(); CreateHud(); + + if (!pDevice->GetOptions()->deferSurfaceCreation) + RecreateSwapChain(false); } @@ -223,9 +223,6 @@ namespace dxvk { m_vsync = vsync; } - if (m_presenter == nullptr) - CreatePresenter(); - HRESULT hr = S_OK; if (!m_presenter->hasSwapChain()) { @@ -395,8 +392,21 @@ namespace dxvk { presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes); presenterDesc.fullScreenExclusive = PickFullscreenMode(); - if (m_presenter->recreateSwapChain(presenterDesc) != VK_SUCCESS) - throw DxvkError("D3D11SwapChain: Failed to recreate swap chain"); + VkResult vr = m_presenter->recreateSwapChain(presenterDesc); + + if (vr == VK_ERROR_SURFACE_LOST_KHR) { + vr = m_presenter->recreateSurface([this] (VkSurfaceKHR* surface) { + return CreateSurface(surface); + }); + + if (vr) + throw DxvkError(str::format("D3D11SwapChain: Failed to recreate surface: ", vr)); + + vr = m_presenter->recreateSwapChain(presenterDesc); + } + + if (vr) + throw DxvkError(str::format("D3D11SwapChain: Failed to recreate swap chain: ", vr)); CreateRenderTargetViews(); } @@ -426,15 +436,22 @@ namespace dxvk { presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes); presenterDesc.fullScreenExclusive = PickFullscreenMode(); - m_presenter = new vk::Presenter(m_window, + m_presenter = new vk::Presenter( m_device->adapter()->vki(), m_device->vkd(), presenterDevice, presenterDesc); m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate); + } - CreateRenderTargetViews(); + + VkResult D3D11SwapChain::CreateSurface(VkSurfaceKHR* pSurface) { + Rc adapter = m_device->adapter(); + + return m_surfaceFactory->CreateSurface( + adapter->vki()->instance(), + adapter->handle(), pSurface); } diff --git a/src/d3d11/d3d11_swapchain.h b/src/d3d11/d3d11_swapchain.h index a7f535f2d..fdf67da2b 100644 --- a/src/d3d11/d3d11_swapchain.h +++ b/src/d3d11/d3d11_swapchain.h @@ -20,7 +20,7 @@ namespace dxvk { D3D11SwapChain( D3D11DXGIDevice* pContainer, D3D11Device* pDevice, - HWND hWnd, + IDXGIVkSurfaceFactory* pSurfaceFactory, const DXGI_SWAP_CHAIN_DESC1* pDesc); ~D3D11SwapChain(); @@ -90,7 +90,7 @@ namespace dxvk { Com m_dxgiDevice; D3D11Device* m_parent; - HWND m_window; + Com m_surfaceFactory; DXGI_SWAP_CHAIN_DESC1 m_desc; @@ -137,6 +137,8 @@ namespace dxvk { void CreatePresenter(); + VkResult CreateSurface(VkSurfaceKHR* pSurface); + void CreateRenderTargetViews(); void CreateBackBuffer(); diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index 59b64073b..807740e74 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -35,9 +35,14 @@ namespace dxvk { m_window = m_presentParams.hDeviceWindow; UpdatePresentRegion(nullptr, nullptr); - if (m_window && !pDevice->GetOptions()->deferSurfaceCreation) + + if (m_window) { CreatePresenter(); + if (!pDevice->GetOptions()->deferSurfaceCreation) + RecreateSwapChain(false); + } + CreateBackBuffers(m_presentParams.BackBufferCount); CreateBlitter(); CreateHud(); @@ -116,7 +121,7 @@ namespace dxvk { bool recreate = false; recreate |= m_presenter == nullptr; - recreate |= window != m_window; + recreate |= window != m_window; recreate |= m_dialog != m_lastDialog; m_window = window; @@ -757,8 +762,21 @@ namespace dxvk { presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes); presenterDesc.fullScreenExclusive = PickFullscreenMode(); - if (m_presenter->recreateSwapChain(presenterDesc) != VK_SUCCESS) - throw DxvkError("D3D9SwapChainEx: Failed to recreate swap chain"); + VkResult vr = m_presenter->recreateSwapChain(presenterDesc); + + if (vr == VK_ERROR_SURFACE_LOST_KHR) { + vr = m_presenter->recreateSurface([this] (VkSurfaceKHR* surface) { + return CreateSurface(surface); + }); + + if (vr) + throw DxvkError(str::format("D3D9SwapChainEx: Failed to recreate surface: ", vr)); + + vr = m_presenter->recreateSwapChain(presenterDesc); + } + + if (vr) + throw DxvkError(str::format("D3D9SwapChainEx: Failed to recreate swap chain: ", vr)); CreateRenderTargetViews(); } @@ -785,15 +803,23 @@ namespace dxvk { presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes); presenterDesc.fullScreenExclusive = PickFullscreenMode(); - m_presenter = new vk::Presenter(m_window, + m_presenter = new vk::Presenter( m_device->adapter()->vki(), m_device->vkd(), presenterDevice, presenterDesc); m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate); + } - CreateRenderTargetViews(); + + VkResult D3D9SwapChainEx::CreateSurface(VkSurfaceKHR* pSurface) { + auto vki = m_device->adapter()->vki(); + + return wsi::createSurface(m_window, + vki->getLoaderProc(), + vki->instance(), + pSurface); } diff --git a/src/d3d9/d3d9_swapchain.h b/src/d3d9/d3d9_swapchain.h index 9eae6a963..2e44a272f 100644 --- a/src/d3d9/d3d9_swapchain.h +++ b/src/d3d9/d3d9_swapchain.h @@ -137,6 +137,8 @@ namespace dxvk { void CreatePresenter(); + VkResult CreateSurface(VkSurfaceKHR* pSurface); + void CreateRenderTargetViews(); void DestroyBackBuffers(); diff --git a/src/vulkan/vulkan_loader.h b/src/vulkan/vulkan_loader.h index 1f0ae7eed..653cf3975 100644 --- a/src/vulkan/vulkan_loader.h +++ b/src/vulkan/vulkan_loader.h @@ -23,6 +23,7 @@ namespace dxvk::vk { ~LibraryLoader(); PFN_vkVoidFunction sym(VkInstance instance, const char* name) const; PFN_vkVoidFunction sym(const char* name) const; + PFN_vkGetInstanceProcAddr getLoaderProc() const { return m_getInstanceProcAddr; } bool valid() const; protected: const HMODULE m_library; @@ -39,6 +40,7 @@ namespace dxvk::vk { struct InstanceLoader : public RcObject { InstanceLoader(const Rc& library, bool owned, VkInstance instance); PFN_vkVoidFunction sym(const char* name) const; + PFN_vkGetInstanceProcAddr getLoaderProc() const { return m_library->getLoaderProc(); } VkInstance instance() const { return m_instance; } protected: Rc m_library; diff --git a/src/vulkan/vulkan_presenter.cpp b/src/vulkan/vulkan_presenter.cpp index c667a815d..860fdbf4d 100644 --- a/src/vulkan/vulkan_presenter.cpp +++ b/src/vulkan/vulkan_presenter.cpp @@ -7,17 +7,12 @@ namespace dxvk::vk { Presenter::Presenter( - HWND window, const Rc& vki, const Rc& vkd, PresenterDevice device, const PresenterDesc& desc) - : m_vki(vki), m_vkd(vkd), m_device(device), m_window(window) { - if (createSurface() != VK_SUCCESS) - throw DxvkError("Failed to create surface"); + : m_vki(vki), m_vkd(vkd), m_device(device) { - if (recreateSwapChain(desc) != VK_SUCCESS) - throw DxvkError("Failed to create swap chain"); } @@ -46,7 +41,7 @@ namespace dxvk::vk { m_swapchain, std::numeric_limits::max(), sync.acquire, VK_NULL_HANDLE, &m_imageIndex); } - + if (m_acquireStatus != VK_SUCCESS && m_acquireStatus != VK_SUBOPTIMAL_KHR) return m_acquireStatus; @@ -88,11 +83,26 @@ namespace dxvk::vk { return status; } - + + VkResult Presenter::recreateSurface( + const std::function& fn) { + if (m_swapchain) + destroySwapchain(); + + if (m_surface) + destroySurface(); + + return fn(&m_surface); + } + + VkResult Presenter::recreateSwapChain(const PresenterDesc& desc) { if (m_swapchain) destroySwapchain(); + if (!m_surface) + return VK_ERROR_SURFACE_LOST_KHR; + // Query surface capabilities. Some properties might // have changed, including the size limits and supported // present modes, so we'll just query everything again. @@ -103,13 +113,13 @@ namespace dxvk::vk { VkResult status; if ((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - m_device.adapter, m_surface, &caps)) != VK_SUCCESS) + m_device.adapter, m_surface, &caps))) return status; - if ((status = getSupportedFormats(formats, desc)) != VK_SUCCESS) + if ((status = getSupportedFormats(formats, desc))) return status; - if ((status = getSupportedPresentModes(modes, desc)) != VK_SUCCESS) + if ((status = getSupportedPresentModes(modes, desc))) return status; // Select actual swap chain properties and create swap chain @@ -155,13 +165,13 @@ namespace dxvk::vk { "\n Exclusive FS: ", desc.fullScreenExclusive)); if ((status = m_vkd->vkCreateSwapchainKHR(m_vkd->device(), - &swapInfo, nullptr, &m_swapchain)) != VK_SUCCESS) + &swapInfo, nullptr, &m_swapchain))) return status; // Acquire images and create views std::vector images; - if ((status = getSwapImages(images)) != VK_SUCCESS) + if ((status = getSwapImages(images))) return status; // Update actual image count @@ -183,7 +193,7 @@ namespace dxvk::vk { 0, 1, 0, 1 }; if ((status = m_vkd->vkCreateImageView(m_vkd->device(), - &viewInfo, nullptr, &m_images[i].view)) != VK_SUCCESS) + &viewInfo, nullptr, &m_images[i].view))) return status; } @@ -194,11 +204,11 @@ namespace dxvk::vk { VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(), - &semInfo, nullptr, &m_semaphores[i].acquire)) != VK_SUCCESS) + &semInfo, nullptr, &m_semaphores[i].acquire))) return status; if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(), - &semInfo, nullptr, &m_semaphores[i].present)) != VK_SUCCESS) + &semInfo, nullptr, &m_semaphores[i].present))) return status; } @@ -398,28 +408,6 @@ namespace dxvk::vk { } - VkResult Presenter::createSurface() { - /* TODO fix */ - VkResult status = wsi::createSurface(m_window, nullptr, m_vki->instance(), &m_surface); - - if (status != VK_SUCCESS) - return status; - - VkBool32 supportStatus = VK_FALSE; - - if ((status = m_vki->vkGetPhysicalDeviceSurfaceSupportKHR(m_device.adapter, - m_device.queueFamily, m_surface, &supportStatus)) != VK_SUCCESS) - return status; - - if (!supportStatus) { - m_vki->vkDestroySurfaceKHR(m_vki->instance(), m_surface, nullptr); - return VK_ERROR_OUT_OF_HOST_MEMORY; // just abuse this - } - - return VK_SUCCESS; - } - - void Presenter::destroySwapchain() { for (const auto& img : m_images) m_vkd->vkDestroyImageView(m_vkd->device(), img.view, nullptr); @@ -440,6 +428,8 @@ namespace dxvk::vk { void Presenter::destroySurface() { m_vki->vkDestroySurfaceKHR(m_vki->instance(), m_surface, nullptr); + + m_surface = VK_NULL_HANDLE; } } diff --git a/src/vulkan/vulkan_presenter.h b/src/vulkan/vulkan_presenter.h index 8df19ea93..858ada308 100644 --- a/src/vulkan/vulkan_presenter.h +++ b/src/vulkan/vulkan_presenter.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "../util/log/log.h" @@ -93,7 +94,6 @@ namespace dxvk::vk { public: Presenter( - HWND window, const Rc& vki, const Rc& vkd, PresenterDevice device, @@ -141,7 +141,16 @@ namespace dxvk::vk { * \returns Status of the operation */ VkResult presentImage(); - + + /** + * \brief Changes and takes ownership of surface + * + * The presenter will destroy the surface as necessary. + * \param [in] fn Surface create function + */ + VkResult recreateSurface( + const std::function& fn); + /** * \brief Changes presenter properties * @@ -149,6 +158,7 @@ namespace dxvk::vk { * no swap chain resources must be in use by the * GPU at the time this is called. * \param [in] desc Swap chain description + * \param [in] surface New Vulkan surface */ VkResult recreateSwapChain( const PresenterDesc& desc); @@ -181,7 +191,6 @@ namespace dxvk::vk { PresenterDevice m_device; PresenterInfo m_info; - HWND m_window = nullptr; VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkSwapchainKHR m_swapchain = VK_NULL_HANDLE; @@ -195,6 +204,9 @@ namespace dxvk::vk { FpsLimiter m_fpsLimiter; + VkResult recreateSwapChainInternal( + const PresenterDesc& desc); + VkResult getSupportedFormats( std::vector& formats, const PresenterDesc& desc);