[PATCH v5 4/6] dxgi: Implement d3d12_swapchain_GetFullscreenState() and d3d12_swapchain_SetFullscreenState().

Józef Kucia jkucia at codeweavers.com
Thu Jun 27 05:42:14 CDT 2019


From: Conor McCarthy <cmccarthy at codeweavers.com>

Signed-off-by: Józef Kucia <jkucia at 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




More information about the wine-devel mailing list