diff --git a/src/dxgi/dxgi_factory.cpp b/src/dxgi/dxgi_factory.cpp index fb9c6d359..af7321210 100644 --- a/src/dxgi/dxgi_factory.cpp +++ b/src/dxgi/dxgi_factory.cpp @@ -207,9 +207,9 @@ namespace dxvk { IUnknown* pDevice, DXGI_SWAP_CHAIN_DESC* pDesc, IDXGISwapChain** ppSwapChain) { - if (ppSwapChain == nullptr || pDesc == nullptr || pDevice == nullptr) + if (!ppSwapChain || !pDesc || !pDesc->OutputWindow || !pDevice) return DXGI_ERROR_INVALID_CALL; - + DXGI_SWAP_CHAIN_DESC1 desc; desc.Width = pDesc->BufferDesc.Width; desc.Height = pDesc->BufferDesc.Height; @@ -222,7 +222,7 @@ namespace dxvk { desc.SwapEffect = pDesc->SwapEffect; desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; desc.Flags = pDesc->Flags; - + DXGI_SWAP_CHAIN_FULLSCREEN_DESC descFs; descFs.RefreshRate = pDesc->BufferDesc.RefreshRate; descFs.ScanlineOrdering = pDesc->BufferDesc.ScanlineOrdering; @@ -230,11 +230,10 @@ namespace dxvk { descFs.Windowed = pDesc->Windowed; IDXGISwapChain1* swapChain = nullptr; - HRESULT hr = CreateSwapChainForHwndBase( - pDevice, pDesc->OutputWindow, - &desc, &descFs, nullptr, - &swapChain); - + + HRESULT hr = CreateSwapChainBase(pDevice, + pDesc->OutputWindow, &desc, &descFs, nullptr, &swapChain); + *ppSwapChain = swapChain; return hr; } @@ -247,73 +246,17 @@ namespace dxvk { const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, IDXGIOutput* pRestrictToOutput, IDXGISwapChain1** ppSwapChain) { - return CreateSwapChainForHwndBase( - pDevice, hWnd, + InitReturnPtr(ppSwapChain); + + if (!ppSwapChain || !pDesc || !hWnd || !pDevice) + return DXGI_ERROR_INVALID_CALL; + + return CreateSwapChainBase(pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); } - HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForHwndBase( - IUnknown* pDevice, - HWND hWnd, - const DXGI_SWAP_CHAIN_DESC1* pDesc, - const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, - IDXGIOutput* pRestrictToOutput, - IDXGISwapChain1** ppSwapChain) { - InitReturnPtr(ppSwapChain); - - if (!ppSwapChain || !pDesc || !hWnd || !pDevice) - return DXGI_ERROR_INVALID_CALL; - - // Make sure the back buffer size is not zero - DXGI_SWAP_CHAIN_DESC1 desc = *pDesc; - wsi::getWindowSize(hWnd, - desc.Width ? nullptr : &desc.Width, - desc.Height ? nullptr : &desc.Height); - - // If necessary, set up a default set of - // fullscreen parameters for the swap chain - DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsDesc; - - if (pFullscreenDesc) { - fsDesc = *pFullscreenDesc; - } else { - fsDesc.RefreshRate = { 0, 0 }; - fsDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - fsDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - fsDesc.Windowed = TRUE; - } - - // Probe various modes to create the swap chain object - Com frontendSwapChain; - - Com dxvkFactory; - - if (SUCCEEDED(pDevice->QueryInterface(IID_PPV_ARGS(&dxvkFactory)))) { - Com surfaceFactory = new DxgiSurfaceFactory( - m_instance->vki()->getLoaderProc(), hWnd); - - Com presenter; - HRESULT hr = dxvkFactory->CreateSwapChain(surfaceFactory.ptr(), &desc, &presenter); - - if (FAILED(hr)) { - Logger::err(str::format("DXGI: CreateSwapChainForHwnd: Failed to create swap chain, hr ", hr)); - return hr; - } - - frontendSwapChain = new DxgiSwapChain(this, presenter.ptr(), hWnd, &desc, &fsDesc, pDevice); - } else { - Logger::err("DXGI: CreateSwapChainForHwnd: Unsupported device type"); - return DXGI_ERROR_UNSUPPORTED; - } - - // Wrap object in swap chain dispatcher - *ppSwapChain = new DxgiSwapChainDispatcher(frontendSwapChain.ref(), pDevice); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForCoreWindow( IUnknown* pDevice, IUnknown* pWindow, @@ -333,9 +276,16 @@ namespace dxvk { IDXGIOutput* pRestrictToOutput, IDXGISwapChain1** ppSwapChain) { InitReturnPtr(ppSwapChain); - - Logger::err("DxgiFactory::CreateSwapChainForComposition: Not implemented"); - return E_NOTIMPL; + + if (!m_options.enableDummyCompositionSwapchain) { + Logger::err("DxgiFactory::CreateSwapChainForComposition: Not implemented"); + return E_NOTIMPL; + } + + Logger::warn("DxgiFactory::CreateSwapChainForComposition: Creating dummy swap chain"); + + return CreateSwapChainBase(pDevice, + nullptr, pDesc, nullptr, pRestrictToOutput, ppSwapChain); } @@ -562,6 +512,62 @@ namespace dxvk { } + HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainBase( + IUnknown* pDevice, + HWND hWnd, + const DXGI_SWAP_CHAIN_DESC1* pDesc, + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, + IDXGIOutput* pRestrictToOutput, + IDXGISwapChain1** ppSwapChain) { + // Make sure the back buffer size is not zero + DXGI_SWAP_CHAIN_DESC1 desc = *pDesc; + + wsi::getWindowSize(hWnd, + desc.Width ? nullptr : &desc.Width, + desc.Height ? nullptr : &desc.Height); + + // If necessary, set up a default set of + // fullscreen parameters for the swap chain + DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsDesc; + + if (pFullscreenDesc) { + fsDesc = *pFullscreenDesc; + } else { + fsDesc.RefreshRate = { 0, 0 }; + fsDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + fsDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + fsDesc.Windowed = TRUE; + } + + // Probe various modes to create the swap chain object + Com frontendSwapChain; + + Com dxvkFactory; + + if (SUCCEEDED(pDevice->QueryInterface(IID_PPV_ARGS(&dxvkFactory)))) { + Com surfaceFactory = new DxgiSurfaceFactory( + m_instance->vki()->getLoaderProc(), hWnd); + + Com presenter; + HRESULT hr = dxvkFactory->CreateSwapChain(surfaceFactory.ptr(), &desc, &presenter); + + if (FAILED(hr)) { + Logger::err(str::format("DXGI: CreateSwapChainForHwnd: Failed to create swap chain, hr ", hr)); + return hr; + } + + frontendSwapChain = new DxgiSwapChain(this, presenter.ptr(), hWnd, &desc, &fsDesc, pDevice); + } else { + Logger::err("DXGI: CreateSwapChainForHwnd: Unsupported device type"); + return DXGI_ERROR_UNSUPPORTED; + } + + // Wrap object in swap chain dispatcher + *ppSwapChain = new DxgiSwapChainDispatcher(frontendSwapChain.ref(), pDevice); + return S_OK; + } + + DXVK_VK_GLOBAL_HDR_STATE DxgiFactory::GlobalHDRState() { std::unique_lock lock(s_globalHDRStateMutex); return s_globalHDRState; diff --git a/src/dxgi/dxgi_factory.h b/src/dxgi/dxgi_factory.h index 280b0a84a..623e133d7 100644 --- a/src/dxgi/dxgi_factory.h +++ b/src/dxgi/dxgi_factory.h @@ -201,7 +201,7 @@ namespace dxvk { BOOL m_monitorFallback; - HRESULT STDMETHODCALLTYPE CreateSwapChainForHwndBase( + HRESULT STDMETHODCALLTYPE CreateSwapChainBase( IUnknown* pDevice, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1* pDesc, diff --git a/src/dxgi/dxgi_surface.cpp b/src/dxgi/dxgi_surface.cpp index b2cc03935..0c11b0c28 100644 --- a/src/dxgi/dxgi_surface.cpp +++ b/src/dxgi/dxgi_surface.cpp @@ -5,13 +5,15 @@ namespace dxvk { DxgiSurfaceFactory::DxgiSurfaceFactory(PFN_vkGetInstanceProcAddr vulkanLoaderProc, HWND hWnd) - : m_vkGetInstanceProcAddr(vulkanLoaderProc), m_window(hWnd) { - + : m_vkGetInstanceProcAddr(vulkanLoaderProc), m_window(hWnd), m_ownsWindow(!hWnd) { + if (!m_window) + m_window = CreateDummyWindow(); } DxgiSurfaceFactory::~DxgiSurfaceFactory() { - + if (m_ownsWindow) + DestroyDummyWindow(); } @@ -44,5 +46,47 @@ namespace dxvk { VkSurfaceKHR* pSurface) { return wsi::createSurface(m_window, m_vkGetInstanceProcAddr, Instance, pSurface); } - -} \ No newline at end of file + + + HWND DxgiSurfaceFactory::CreateDummyWindow() { +#ifdef _WIN32 + static std::atomic s_wndClassRegistered = { false }; + + HINSTANCE hInstance = ::GetModuleHandle(nullptr); + + if (!s_wndClassRegistered.load(std::memory_order_acquire)) { + WNDCLASSEXW wndClass = { }; + wndClass.cbSize = sizeof(wndClass); + wndClass.style = CS_HREDRAW | CS_VREDRAW; + wndClass.lpfnWndProc = &::DefWindowProcW; + wndClass.hInstance = hInstance; + wndClass.lpszClassName = L"DXVKDUMMYWNDCLASS"; + + ATOM atom = ::RegisterClassExW(&wndClass); + + if (!atom) + Logger::warn("DxgiSurfaceFactory: Failed to register dummy window class"); + + s_wndClassRegistered.store(!!atom, std::memory_order_release); + } + + HWND hWnd = ::CreateWindowW(L"DXVKDUMMYWNDCLASS", L"DXVKDUMMYWINDOW", + WS_OVERLAPPEDWINDOW, 0, 0, 320, 240, nullptr, nullptr, hInstance, nullptr); + + if (!hWnd) + Logger::err("DxgiSurfaceFactory: Failed to create dummy window"); + + return hWnd; +#else + return nullptr; +#endif + } + + + void DxgiSurfaceFactory::DestroyDummyWindow() { +#ifdef _WIN32 + DestroyWindow(m_window); +#endif + } + +} diff --git a/src/dxgi/dxgi_surface.h b/src/dxgi/dxgi_surface.h index 25a845fdd..4a5c36f6d 100644 --- a/src/dxgi/dxgi_surface.h +++ b/src/dxgi/dxgi_surface.h @@ -35,9 +35,14 @@ namespace dxvk { private: - PFN_vkGetInstanceProcAddr m_vkGetInstanceProcAddr; - HWND m_window; + PFN_vkGetInstanceProcAddr m_vkGetInstanceProcAddr = nullptr; + HWND m_window = nullptr; + bool m_ownsWindow = false; + + HWND CreateDummyWindow(); + + void DestroyDummyWindow(); }; -} \ No newline at end of file +}