From: Conor McCarthy <cmccarthy(a)codeweavers.com>
Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com>
---
dlls/dxgi/swapchain.c | 133 +++++++++++++++++++++++++++++++++++++++--
dlls/dxgi/tests/dxgi.c | 40 ++++++-------
2 files changed, 149 insertions(+), 24 deletions(-)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 0491040909d3..2a4c01278bed 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -1085,8 +1085,12 @@ struct d3d12_swapchain
IWineDXGIFactory *factory;
HWND window;
+ IDXGIOutput *target;
DXGI_SWAP_CHAIN_DESC1 desc;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc;
+ struct wined3d_window_state window_state;
+ DXGI_MODE_DESC original_mode;
+ RECT original_window_rect;
};
static DXGI_FORMAT dxgi_format_from_vk_format(VkFormat vk_format)
@@ -1880,6 +1884,12 @@ static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain)
if (swapchain->vk_instance)
vk_funcs->p_vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL);
+ if (swapchain->target)
+ {
+ WARN("Destroying fullscreen swapchain.\n");
+ IDXGIOutput_Release(swapchain->target);
+ }
+
if (swapchain->device)
ID3D12Device_Release(swapchain->device);
@@ -2178,17 +2188,112 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBuffer(IDXGISwapChain3 *ifac
static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreenState(IDXGISwapChain3 *iface,
BOOL fullscreen, IDXGIOutput *target)
{
- FIXME("iface %p, fullscreen %#x, target %p stub!\n", iface, fullscreen, target);
+ struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
+ DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc = &swapchain->fullscreen_desc;
+ const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc = &swapchain->desc;
+ HWND window = swapchain->window;
+ DXGI_MODE_DESC mode;
+ HRESULT hr = S_OK;
- return E_NOTIMPL;
+ TRACE("iface %p, fullscreen %#x, target %p.\n", iface, fullscreen, target);
+
+ if (!fullscreen && target)
+ {
+ WARN("Invalid call.\n");
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+ if (target)
+ {
+ IDXGIOutput_AddRef(target);
+ }
+ else if (FAILED(hr = IDXGISwapChain3_GetContainingOutput(iface, &target)))
+ {
+ WARN("Failed to get target output for swapchain, hr %#x.\n", hr);
+ return hr;
+ }
+
+ if (swapchain_desc->Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)
+ {
+ if (fullscreen)
+ {
+ mode.Width = swapchain_desc->Width;
+ mode.Height = swapchain_desc->Height;
+ mode.RefreshRate = fullscreen_desc->RefreshRate;
+ mode.Format = swapchain_desc->Format;
+ mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+ }
+ else
+ {
+ mode = swapchain->original_mode;
+ }
+
+ if (FAILED(hr = dxgi_output_set_display_mode(target, &mode)))
+ goto fail;
+ }
+ else if (FAILED(hr = dxgi_output_get_display_mode(target, &mode)))
+ {
+ WARN("Failed to get display mode, hr %#x.\n", hr);
+ hr = DXGI_ERROR_INVALID_CALL;
+ goto fail;
+ }
+
+ if (fullscreen)
+ {
+ if (fullscreen_desc->Windowed)
+ {
+ if (FAILED(hr = wined3d_window_state_setup_fullscreen(&swapchain->window_state,
+ window, mode.Width, mode.Height)))
+ goto fail;
+ }
+ else
+ {
+ /* Fullscreen -> fullscreen mode change */
+ MoveWindow(window, 0, 0, mode.Width, mode.Height, TRUE);
+ ShowWindow(window, SW_SHOW);
+ }
+ }
+ else if (!fullscreen_desc->Windowed)
+ {
+ /* Fullscreen -> windowed switch */
+ wined3d_window_state_restore_from_fullscreen(&swapchain->window_state,
+ window, &swapchain->original_window_rect);
+ }
+
+ fullscreen_desc->Windowed = !fullscreen;
+
+ if (!fullscreen)
+ {
+ IDXGIOutput_Release(target);
+ target = NULL;
+ }
+
+ if (swapchain->target)
+ IDXGIOutput_Release(swapchain->target);
+ swapchain->target = target;
+
+ return S_OK;
+
+fail:
+ IDXGIOutput_Release(target);
+
+ return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
}
static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenState(IDXGISwapChain3 *iface,
BOOL *fullscreen, IDXGIOutput **target)
{
- FIXME("iface %p, fullscreen %p, target %p stub!\n", iface, fullscreen, target);
+ struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
- return E_NOTIMPL;
+ TRACE("iface %p, fullscreen %p, target %p.\n", iface, fullscreen, target);
+
+ if (fullscreen)
+ *fullscreen = !swapchain->fullscreen_desc.Windowed;
+
+ if (target && (*target = swapchain->target))
+ IDXGIOutput_AddRef(*target);
+
+ return S_OK;
}
static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDesc(IDXGISwapChain3 *iface, DXGI_SWAP_CHAIN_DESC *desc)
@@ -2306,6 +2411,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetContainingOutput(IDXGISwapCh
TRACE("iface %p, output %p.\n", iface, output);
+ if (swapchain->target)
+ {
+ IDXGIOutput_AddRef(*output = swapchain->target);
+ return S_OK;
+ }
+
device_parent = vkd3d_get_device_parent(swapchain->device);
if (SUCCEEDED(hr = IUnknown_QueryInterface(device_parent, &IID_IDXGIAdapter, (void **)&adapter)))
@@ -2736,6 +2847,7 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
uint32_t queue_family_index;
VkSurfaceKHR vk_surface;
VkInstance vk_instance;
+ IDXGIOutput *output;
VkBool32 supported;
VkDevice vk_device;
VkFence vk_fence;
@@ -2853,6 +2965,19 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
return hresult_from_vk_result(vr);
}
+ GetWindowRect(window, &swapchain->original_window_rect);
+ if (SUCCEEDED(hr = d3d12_swapchain_GetContainingOutput(&swapchain->IDXGISwapChain3_iface, &output)))
+ {
+ hr = dxgi_output_get_display_mode(output, &swapchain->original_mode);
+ IDXGIOutput_Release(output);
+ }
+ if (FAILED(hr))
+ {
+ WARN("Failed to get current display mode, hr %#x.\n", hr);
+ d3d12_swapchain_destroy(swapchain);
+ return hr;
+ }
+
IWineDXGIFactory_AddRef(swapchain->factory = factory);
return S_OK;
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index d8176bb1c054..7ba417010dd6 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -4155,7 +4155,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
skip("Test %u: Could not change fullscreen state.\n", i);
continue;
}
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
@@ -4163,23 +4163,23 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
output = NULL;
fullscreen = FALSE;
hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
- todo_wine_if(is_d3d12) ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
- todo_wine_if(is_d3d12) ok(!!output, "Test %u: Got unexpected output.\n", i);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
+ ok(!!output, "Test %u: Got unexpected output.\n", i);
if (output)
IDXGIOutput_ReleaseOwnership(output);
/* Still fullscreen. */
fullscreen = FALSE;
hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
- todo_wine_if(is_d3d12) ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
/* Calling IDXGISwapChain_Present() will exit fullscreen. */
hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
fullscreen = TRUE;
hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
/* Now fullscreen mode is exited. */
if (!flags[i] && !is_d3d12)
/* Still fullscreen on vista and 2008. */
@@ -4198,11 +4198,11 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
* compositing. D3d12 fullscreen mode acts just like borderless
* fullscreen window mode. */
hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
fullscreen = FALSE;
hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
- todo_wine_if(is_d3d12) ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
todo_wine_if(!is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
@@ -4217,8 +4217,8 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
fullscreen = FALSE;
hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
- todo_wine_if(is_d3d12) ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
/* A visible, but with bottom z-order window still causes the
* swapchain to exit fullscreen mode. */
SetWindowPos(occluding_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
@@ -4231,7 +4231,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
* for d3d12. */
fullscreen = TRUE;
hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
"Test %u: Got unexpected fullscreen status.\n", i);
@@ -4243,7 +4243,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
fullscreen = TRUE;
hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
if (flags[i] == DXGI_PRESENT_TEST)
todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
"Test %u: Got unexpected fullscreen status.\n", i);
@@ -4267,7 +4267,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
* IDXGISwapChain_GetFullscreenState() before IDXGISwapChain_Present(). */
ShowWindow(occluding_window, SW_HIDE);
hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
ShowWindow(occluding_window, SW_SHOW);
hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
@@ -4302,7 +4302,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
}
fullscreen = TRUE;
hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
todo_wine ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
DestroyWindow(occluding_window);
@@ -4312,7 +4312,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
}
@@ -5553,11 +5553,11 @@ static void test_output_ownership(IUnknown *device, BOOL is_d3d12)
skip("Failed to change fullscreen state.\n");
goto done;
}
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
fullscreen = FALSE;
hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
- todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
- todo_wine_if(is_d3d12) ok(fullscreen, "Got unexpected fullscreen state.\n");
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(fullscreen, "Got unexpected fullscreen state.\n");
if (is_d3d12)
wait_vidpn_exclusive_ownership(&check_ownership_desc, STATUS_SUCCESS, FALSE);
else
--
2.21.0