mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-06 20:58:37 +01:00
[dxgi] Create dummy window for composition swap chains
Obviously not a valid implementation, but allows composition swap chains to exist with some basic functionality.
This commit is contained in:
parent
76f9bec7cc
commit
f615594f22
4 changed files with 137 additions and 82 deletions
|
@ -207,7 +207,7 @@ namespace dxvk {
|
||||||
IUnknown* pDevice,
|
IUnknown* pDevice,
|
||||||
DXGI_SWAP_CHAIN_DESC* pDesc,
|
DXGI_SWAP_CHAIN_DESC* pDesc,
|
||||||
IDXGISwapChain** ppSwapChain) {
|
IDXGISwapChain** ppSwapChain) {
|
||||||
if (ppSwapChain == nullptr || pDesc == nullptr || pDevice == nullptr)
|
if (!ppSwapChain || !pDesc || !pDesc->OutputWindow || !pDevice)
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
DXGI_SWAP_CHAIN_DESC1 desc;
|
DXGI_SWAP_CHAIN_DESC1 desc;
|
||||||
|
@ -230,10 +230,9 @@ namespace dxvk {
|
||||||
descFs.Windowed = pDesc->Windowed;
|
descFs.Windowed = pDesc->Windowed;
|
||||||
|
|
||||||
IDXGISwapChain1* swapChain = nullptr;
|
IDXGISwapChain1* swapChain = nullptr;
|
||||||
HRESULT hr = CreateSwapChainForHwndBase(
|
|
||||||
pDevice, pDesc->OutputWindow,
|
HRESULT hr = CreateSwapChainBase(pDevice,
|
||||||
&desc, &descFs, nullptr,
|
pDesc->OutputWindow, &desc, &descFs, nullptr, &swapChain);
|
||||||
&swapChain);
|
|
||||||
|
|
||||||
*ppSwapChain = swapChain;
|
*ppSwapChain = swapChain;
|
||||||
return hr;
|
return hr;
|
||||||
|
@ -244,19 +243,6 @@ namespace dxvk {
|
||||||
IUnknown* pDevice,
|
IUnknown* pDevice,
|
||||||
HWND hWnd,
|
HWND hWnd,
|
||||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
|
||||||
IDXGIOutput* pRestrictToOutput,
|
|
||||||
IDXGISwapChain1** ppSwapChain) {
|
|
||||||
return CreateSwapChainForHwndBase(
|
|
||||||
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,
|
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||||
IDXGIOutput* pRestrictToOutput,
|
IDXGIOutput* pRestrictToOutput,
|
||||||
IDXGISwapChain1** ppSwapChain) {
|
IDXGISwapChain1** ppSwapChain) {
|
||||||
|
@ -265,52 +251,9 @@ namespace dxvk {
|
||||||
if (!ppSwapChain || !pDesc || !hWnd || !pDevice)
|
if (!ppSwapChain || !pDesc || !hWnd || !pDevice)
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
// Make sure the back buffer size is not zero
|
return CreateSwapChainBase(pDevice, hWnd,
|
||||||
DXGI_SWAP_CHAIN_DESC1 desc = *pDesc;
|
pDesc, pFullscreenDesc, pRestrictToOutput,
|
||||||
|
ppSwapChain);
|
||||||
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<IDXGISwapChain4> frontendSwapChain;
|
|
||||||
|
|
||||||
Com<IDXGIVkSwapChainFactory> dxvkFactory;
|
|
||||||
|
|
||||||
if (SUCCEEDED(pDevice->QueryInterface(IID_PPV_ARGS(&dxvkFactory)))) {
|
|
||||||
Com<IDXGIVkSurfaceFactory> surfaceFactory = new DxgiSurfaceFactory(
|
|
||||||
m_instance->vki()->getLoaderProc(), hWnd);
|
|
||||||
|
|
||||||
Com<IDXGIVkSwapChain> 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -334,8 +277,15 @@ namespace dxvk {
|
||||||
IDXGISwapChain1** ppSwapChain) {
|
IDXGISwapChain1** ppSwapChain) {
|
||||||
InitReturnPtr(ppSwapChain);
|
InitReturnPtr(ppSwapChain);
|
||||||
|
|
||||||
Logger::err("DxgiFactory::CreateSwapChainForComposition: Not implemented");
|
if (!m_options.enableDummyCompositionSwapchain) {
|
||||||
return E_NOTIMPL;
|
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<IDXGISwapChain4> frontendSwapChain;
|
||||||
|
|
||||||
|
Com<IDXGIVkSwapChainFactory> dxvkFactory;
|
||||||
|
|
||||||
|
if (SUCCEEDED(pDevice->QueryInterface(IID_PPV_ARGS(&dxvkFactory)))) {
|
||||||
|
Com<IDXGIVkSurfaceFactory> surfaceFactory = new DxgiSurfaceFactory(
|
||||||
|
m_instance->vki()->getLoaderProc(), hWnd);
|
||||||
|
|
||||||
|
Com<IDXGIVkSwapChain> 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() {
|
DXVK_VK_GLOBAL_HDR_STATE DxgiFactory::GlobalHDRState() {
|
||||||
std::unique_lock lock(s_globalHDRStateMutex);
|
std::unique_lock lock(s_globalHDRStateMutex);
|
||||||
return s_globalHDRState;
|
return s_globalHDRState;
|
||||||
|
|
|
@ -201,7 +201,7 @@ namespace dxvk {
|
||||||
BOOL m_monitorFallback;
|
BOOL m_monitorFallback;
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE CreateSwapChainForHwndBase(
|
HRESULT STDMETHODCALLTYPE CreateSwapChainBase(
|
||||||
IUnknown* pDevice,
|
IUnknown* pDevice,
|
||||||
HWND hWnd,
|
HWND hWnd,
|
||||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||||
|
|
|
@ -5,13 +5,15 @@
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
DxgiSurfaceFactory::DxgiSurfaceFactory(PFN_vkGetInstanceProcAddr vulkanLoaderProc, HWND hWnd)
|
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() {
|
DxgiSurfaceFactory::~DxgiSurfaceFactory() {
|
||||||
|
if (m_ownsWindow)
|
||||||
|
DestroyDummyWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,4 +47,46 @@ namespace dxvk {
|
||||||
return wsi::createSurface(m_window, m_vkGetInstanceProcAddr, Instance, pSurface);
|
return wsi::createSurface(m_window, m_vkGetInstanceProcAddr, Instance, pSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HWND DxgiSurfaceFactory::CreateDummyWindow() {
|
||||||
|
#ifdef _WIN32
|
||||||
|
static std::atomic<bool> 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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -35,8 +35,13 @@ namespace dxvk {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
PFN_vkGetInstanceProcAddr m_vkGetInstanceProcAddr;
|
PFN_vkGetInstanceProcAddr m_vkGetInstanceProcAddr = nullptr;
|
||||||
HWND m_window;
|
HWND m_window = nullptr;
|
||||||
|
bool m_ownsWindow = false;
|
||||||
|
|
||||||
|
HWND CreateDummyWindow();
|
||||||
|
|
||||||
|
void DestroyDummyWindow();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue