From: Józef Kucia Subject: [PATCH v5 4/6] dxgi: Implement d3d12_swapchain_GetFullscreenState() and d3d12_swapchain_SetFullscreenState(). Message-Id: <20190627104216.25867-4-jkucia@codeweavers.com> Date: Thu, 27 Jun 2019 12:42:14 +0200 From: Conor McCarthy Signed-off-by: Józef Kucia --- 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