From: Stefan Dösinger stefan@codeweavers.com
--- dlls/dxgi/dxgi_private.h | 1 + dlls/dxgi/swapchain.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+)
diff --git a/dlls/dxgi/dxgi_private.h b/dlls/dxgi/dxgi_private.h index dd17e39eca6..0e47859a445 100644 --- a/dlls/dxgi/dxgi_private.h +++ b/dlls/dxgi/dxgi_private.h @@ -183,6 +183,7 @@ struct d3d11_swapchain
IDXGIOutput *target; LONG present_count; + LONG nested_sfs; };
HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_device *device, diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 9677142e0af..e3d335c5474 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -383,6 +383,8 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_SetFullscreen struct wined3d_swapchain_desc swapchain_desc; struct wined3d_swapchain_state *state; struct dxgi_output *dxgi_output; + LONG nested_sfs; + BOOL old_fs; HRESULT hr;
TRACE("iface %p, fullscreen %#x, target %p.\n", iface, fullscreen, target); @@ -404,6 +406,19 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_SetFullscreen } dxgi_output = unsafe_impl_from_IDXGIOutput(target);
+ /* DXGI catches nested SetFullscreenState invocations, earlier versions of d3d + * do not. Final Fantasy XIV depends on this behavior. It tries to call SFS on + * WM_WINDOWPOSCHANGED messages. */ + nested_sfs = InterlockedExchange(&swapchain->nested_sfs, 1); + + if (nested_sfs) + { + WARN("Nested invocation of SetFullscreenState.\n"); + IDXGIOutput_Release(target); + IDXGISwapChain1_GetFullscreenState(iface, &old_fs, NULL); + return old_fs == fullscreen ? S_OK : DXGI_STATUS_MODE_CHANGE_IN_PROGRESS; + } + wined3d_mutex_lock(); state = wined3d_swapchain_get_state(swapchain->wined3d_swapchain); wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &swapchain_desc); @@ -411,6 +426,9 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_SetFullscreen swapchain_desc.windowed = !fullscreen; hr = wined3d_swapchain_state_set_fullscreen(state, &swapchain_desc, NULL); wined3d_mutex_unlock(); + + nested_sfs = InterlockedExchange(&swapchain->nested_sfs, 0); + if (FAILED(hr)) { IDXGIOutput_Release(target); @@ -1015,6 +1033,7 @@ struct d3d12_swapchain IDXGIOutput *target; DXGI_SWAP_CHAIN_DESC1 desc; DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc; + LONG nested_sfs;
ID3D12Fence *frame_latency_fence; HANDLE frame_latency_event; @@ -2173,6 +2192,8 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreen const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc = &swapchain->desc; struct wined3d_swapchain_desc wined3d_desc; HWND window = swapchain->window; + LONG nested_sfs; + BOOL old_fs; HRESULT hr;
TRACE("iface %p, fullscreen %#x, target %p.\n", iface, fullscreen, target); @@ -2196,10 +2217,24 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreen if (FAILED(hr = wined3d_swapchain_desc_from_dxgi(&wined3d_desc, target, window, swapchain_desc, fullscreen_desc))) goto fail; + + nested_sfs = InterlockedExchange(&swapchain->nested_sfs, 1); + + if (nested_sfs) + { + WARN("Nested invocation of SetFullscreenState.\n"); + IDXGIOutput_Release(target); + IDXGISwapChain4_GetFullscreenState(iface, &old_fs, NULL); + return old_fs == fullscreen ? S_OK : DXGI_STATUS_MODE_CHANGE_IN_PROGRESS; + } + wined3d_mutex_lock(); wined3d_desc.windowed = !fullscreen; hr = wined3d_swapchain_state_set_fullscreen(swapchain->state, &wined3d_desc, NULL); wined3d_mutex_unlock(); + + InterlockedExchange(&swapchain->nested_sfs, 0); + if (FAILED(hr)) goto fail;