[PATCH 5/7] dxgi: Implement d3d12_swapchain_SetFullscreenState().

Henri Verbeet hverbeet at codeweavers.com
Wed Jul 31 15:29:49 CDT 2019


From: Conor McCarthy <cmccarthy at codeweavers.com>

Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
This supersedes patch 167239.

 dlls/dxgi/swapchain.c          | 146 ++++++++++++++++++++++++++++++++++-------
 dlls/dxgi/tests/dxgi.c         |  34 +++++-----
 dlls/wined3d/device.c          |   3 +-
 dlls/wined3d/swapchain.c       | 137 +++++++++++++++++++++-----------------
 dlls/wined3d/wined3d.spec      |   4 +-
 dlls/wined3d/wined3d_main.c    |   3 +-
 dlls/wined3d/wined3d_private.h |   5 +-
 include/wine/wined3d.h         |   7 +-
 8 files changed, 230 insertions(+), 109 deletions(-)

diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 0871200ff7c..c76ad1d1359 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -152,6 +152,24 @@ static HRESULT dxgi_get_output_from_window(IDXGIAdapter *adapter, HWND window, I
     return DXGI_ERROR_NOT_FOUND;
 }
 
+static HRESULT dxgi_swapchain_set_fullscreen_state(struct wined3d_swapchain_state *state,
+        const struct wined3d_swapchain_desc *swapchain_desc, IDXGIOutput *output)
+{
+    struct dxgi_output *dxgi_output;
+    struct dxgi_adapter *adapter;
+    HRESULT hr;
+
+    dxgi_output = unsafe_impl_from_IDXGIOutput(output);
+    adapter = dxgi_output->adapter;
+
+    wined3d_mutex_lock();
+    hr = wined3d_swapchain_state_set_fullscreen(state, swapchain_desc,
+            adapter->factory->wined3d, adapter->ordinal, NULL);
+    wined3d_mutex_unlock();
+
+    return hr;
+}
+
 static HRESULT dxgi_swapchain_resize_target(IDXGISwapChain1 *swapchain,
         struct wined3d_swapchain_state *state, const DXGI_MODE_DESC *target_mode_desc)
 {
@@ -391,6 +409,7 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_SetFullscreen
 {
     struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
     struct wined3d_swapchain_desc swapchain_desc;
+    struct wined3d_swapchain_state *state;
     HRESULT hr;
 
     TRACE("iface %p, fullscreen %#x, target %p.\n", iface, fullscreen, target);
@@ -401,31 +420,35 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_SetFullscreen
         return DXGI_ERROR_INVALID_CALL;
     }
 
-    if (fullscreen)
+    if (target)
     {
-        if (target)
-        {
-            IDXGIOutput_AddRef(target);
-        }
-        else if (FAILED(hr = IDXGISwapChain1_GetContainingOutput(iface, &target)))
-        {
-            WARN("Failed to get default target output for swapchain, hr %#x.\n", hr);
-            return hr;
-        }
+        IDXGIOutput_AddRef(target);
+    }
+    else if (FAILED(hr = IDXGISwapChain1_GetContainingOutput(iface, &target)))
+    {
+        WARN("Failed to get target output for swapchain, hr %#x.\n", hr);
+        return hr;
     }
 
     wined3d_mutex_lock();
+    state = wined3d_swapchain_get_state(swapchain->wined3d_swapchain);
     wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &swapchain_desc);
     swapchain_desc.windowed = !fullscreen;
-    hr = wined3d_swapchain_set_fullscreen(swapchain->wined3d_swapchain, &swapchain_desc, NULL);
+    hr = dxgi_swapchain_set_fullscreen_state(state, &swapchain_desc, target);
     wined3d_mutex_unlock();
     if (FAILED(hr))
     {
-        if (target)
-            IDXGIOutput_Release(target);
+        IDXGIOutput_Release(target);
+
         return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
     }
 
+    if (!fullscreen)
+    {
+        IDXGIOutput_Release(target);
+        target = NULL;
+    }
+
     if (swapchain->target)
         IDXGIOutput_Release(swapchain->target);
     swapchain->target = target;
@@ -866,22 +889,27 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi
     swapchain->target = NULL;
     if (fullscreen)
     {
+        struct wined3d_swapchain_state *state;
+
         desc->windowed = FALSE;
-        if (FAILED(hr = wined3d_swapchain_set_fullscreen(swapchain->wined3d_swapchain,
-                desc, NULL)))
+        state = wined3d_swapchain_get_state(swapchain->wined3d_swapchain);
+
+        if (FAILED(hr = IDXGISwapChain1_GetContainingOutput(&swapchain->IDXGISwapChain1_iface,
+                &swapchain->target)))
         {
-            WARN("Failed to set fullscreen state, hr %#x.\n", hr);
+            WARN("Failed to get target output for fullscreen swapchain, hr %#x.\n", hr);
             wined3d_swapchain_decref(swapchain->wined3d_swapchain);
             goto cleanup;
         }
 
-        if (FAILED(hr = IDXGISwapChain1_GetContainingOutput(&swapchain->IDXGISwapChain1_iface,
-                &swapchain->target)))
+        if (FAILED(hr = dxgi_swapchain_set_fullscreen_state(state, desc, swapchain->target)))
         {
-            WARN("Failed to get target output for fullscreen swapchain, hr %#x.\n", hr);
+            WARN("Failed to set fullscreen state, hr %#x.\n", hr);
+            IDXGIOutput_Release(swapchain->target);
             wined3d_swapchain_decref(swapchain->wined3d_swapchain);
             goto cleanup;
         }
+
     }
     wined3d_mutex_unlock();
 
@@ -1067,6 +1095,7 @@ struct d3d12_swapchain
     IWineDXGIFactory *factory;
 
     HWND window;
+    IDXGIOutput *target;
     DXGI_SWAP_CHAIN_DESC1 desc;
     DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc;
 };
@@ -1865,6 +1894,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);
 
@@ -2165,9 +2200,57 @@ 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;
+    struct wined3d_swapchain_desc wined3d_desc;
+    HWND window = swapchain->window;
+    HRESULT hr;
 
-    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 (FAILED(hr = wined3d_swapchain_desc_from_dxgi(&wined3d_desc, window, swapchain_desc, fullscreen_desc)))
+        goto fail;
+    wined3d_mutex_lock();
+    wined3d_desc.windowed = !fullscreen;
+    hr = dxgi_swapchain_set_fullscreen_state(swapchain->state, &wined3d_desc, target);
+    wined3d_mutex_unlock();
+    if (FAILED(hr))
+        goto fail;
+
+    fullscreen_desc->Windowed = wined3d_desc.windowed;
+    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,
@@ -2180,8 +2263,8 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenState(IDXGISwapCha
     if (fullscreen)
         *fullscreen = !swapchain->fullscreen_desc.Windowed;
 
-    if (target)
-        *target = NULL;
+    if (target && (*target = swapchain->target))
+        IDXGIOutput_AddRef(*target);
 
     return S_OK;
 }
@@ -2299,6 +2382,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)))
@@ -2726,10 +2815,13 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
     struct wined3d_swapchain_desc wined3d_desc;
     VkWin32SurfaceCreateInfoKHR surface_desc;
     VkPhysicalDevice vk_physical_device;
+    struct dxgi_adapter *dxgi_adapter;
     VkFenceCreateInfo fence_desc;
     uint32_t queue_family_index;
     VkSurfaceKHR vk_surface;
+    IUnknown *device_parent;
     VkInstance vk_instance;
+    IDXGIAdapter *adapter;
     VkBool32 supported;
     VkDevice vk_device;
     VkFence vk_fence;
@@ -2768,9 +2860,15 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
         return DXGI_ERROR_UNSUPPORTED;
     }
 
+    device_parent = vkd3d_get_device_parent(device);
+    if (FAILED(hr = IUnknown_QueryInterface(device_parent, &IID_IDXGIAdapter, (void **)&adapter)))
+        return hr;
+    dxgi_adapter = unsafe_impl_from_IDXGIAdapter(adapter);
+    IDXGIAdapter_Release(adapter);
     if (FAILED(hr = wined3d_swapchain_desc_from_dxgi(&wined3d_desc, window, swapchain_desc, fullscreen_desc)))
         return hr;
-    if (FAILED(hr = wined3d_swapchain_state_create(&wined3d_desc, window, &swapchain->state)))
+    if (FAILED(hr = wined3d_swapchain_state_create(&wined3d_desc, window,
+            dxgi_adapter->factory->wined3d, dxgi_adapter->ordinal, &swapchain->state)))
         return hr;
 
     if (swapchain_desc->BufferUsage && swapchain_desc->BufferUsage != DXGI_USAGE_RENDER_TARGET_OUTPUT)
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 5f5bb1e33d7..2d4a5d460b0 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]);
@@ -4164,8 +4164,8 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
         fullscreen = FALSE;
         hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
         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(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
+        ok(!!output, "Test %u: Got unexpected output.\n", i);
 
         if (output)
             IDXGIOutput_ReleaseOwnership(output);
@@ -4173,7 +4173,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
         fullscreen = FALSE;
         hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
         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(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);
@@ -4185,7 +4185,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
             /* Still fullscreen on vista and 2008. */
             todo_wine ok(!fullscreen || broken(fullscreen), "Test %u: Got unexpected fullscreen status.\n", i);
         else
-            todo_wine_if(is_d3d12) ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
+            ok(fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
         if (output)
             IDXGIOutput_Release(output);
 
@@ -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);
         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(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]);
@@ -4218,7 +4218,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
         fullscreen = FALSE;
         hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
         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(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);
@@ -4232,7 +4232,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
         fullscreen = TRUE;
         hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
         ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
-        todo_wine ok(is_d3d12 ? fullscreen : !fullscreen,
+        todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
                 "Test %u: Got unexpected fullscreen status.\n", i);
 
         hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
@@ -4245,10 +4245,10 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
         hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
         ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
         if (flags[i] == DXGI_PRESENT_TEST)
-            todo_wine ok(is_d3d12 ? fullscreen : !fullscreen,
+            todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen,
                     "Test %u: Got unexpected fullscreen status.\n", i);
         else
-            todo_wine_if(!is_d3d12) ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
+            todo_wine ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
 
         /* Even though d3d12 doesn't exit fullscreen, a
          * IDXGISwapChain_ResizeBuffers() is still needed for subsequent
@@ -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);
@@ -4303,7 +4303,7 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
         fullscreen = TRUE;
         hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
         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 ok(!fullscreen, "Test %u: Got unexpected fullscreen status.\n", i);
 
         DestroyWindow(occluding_window);
         hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
@@ -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);
     }
@@ -5558,11 +5558,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
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index db1b313fcbf..2c05209ea26 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -5428,7 +5428,8 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
                 return hr;
             }
         }
-        if (FAILED(hr = wined3d_swapchain_set_fullscreen(swapchain, swapchain_desc, mode)))
+        if (FAILED(hr = wined3d_swapchain_state_set_fullscreen(&swapchain->state,
+                swapchain_desc, device->wined3d, device->adapter->ordinal, mode)))
             return hr;
 
         /* Switch from fullscreen to windowed. */
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 333c3153f68..37b0a78e386 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -80,13 +80,13 @@ static void swapchain_cleanup(struct wined3d_swapchain *swapchain)
         if (swapchain->state.desc.auto_restore_display_mode)
         {
             if (FAILED(hr = wined3d_set_adapter_display_mode(swapchain->device->wined3d,
-                    swapchain->device->adapter->ordinal, &swapchain->original_mode)))
+                    swapchain->device->adapter->ordinal, &swapchain->state.original_mode)))
                 ERR("Failed to restore display mode, hr %#x.\n", hr);
 
             if (swapchain->state.desc.flags & WINED3D_SWAPCHAIN_RESTORE_WINDOW_RECT)
             {
                 wined3d_swapchain_state_restore_from_fullscreen(&swapchain->state,
-                        swapchain->state.device_window, &swapchain->original_window_rect);
+                        swapchain->state.device_window, &swapchain->state.original_window_rect);
                 wined3d_device_release_focus_window(swapchain->device);
             }
         }
@@ -736,16 +736,53 @@ void swapchain_set_max_frame_latency(struct wined3d_swapchain *swapchain, const
     swapchain->max_frame_latency = device->max_frame_latency >= 2 ? device->max_frame_latency - 1 : 1;
 }
 
-static enum wined3d_format_id adapter_format_from_backbuffer_format(struct wined3d_swapchain *swapchain,
+static enum wined3d_format_id adapter_format_from_backbuffer_format(const struct wined3d_adapter *adapter,
         enum wined3d_format_id format_id)
 {
-    const struct wined3d_adapter *adapter = swapchain->device->adapter;
     const struct wined3d_format *backbuffer_format;
 
     backbuffer_format = wined3d_get_format(adapter, format_id, WINED3D_BIND_RENDER_TARGET);
     return pixelformat_for_depth(backbuffer_format->byte_count * CHAR_BIT);
 }
 
+static HRESULT wined3d_swapchain_state_init(struct wined3d_swapchain_state *state,
+        const struct wined3d_swapchain_desc *desc, HWND window,
+        struct wined3d *wined3d, unsigned int adapter_idx)
+{
+    HRESULT hr;
+
+    state->desc = *desc;
+
+    if (FAILED(hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &state->original_mode, NULL)))
+    {
+        ERR("Failed to get current display mode, hr %#x.\n", hr);
+        return hr;
+    }
+
+    if (!desc->windowed)
+    {
+        if (desc->flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH)
+        {
+            struct wined3d_adapter *adapter = wined3d->adapters[adapter_idx];
+
+            state->d3d_mode.width = desc->backbuffer_width;
+            state->d3d_mode.height = desc->backbuffer_height;
+            state->d3d_mode.format_id = adapter_format_from_backbuffer_format(adapter, desc->backbuffer_format);
+            state->d3d_mode.refresh_rate = desc->refresh_rate;
+            state->d3d_mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
+        }
+        else
+        {
+            state->d3d_mode = state->original_mode;
+        }
+    }
+
+    GetWindowRect(window, &state->original_window_rect);
+    state->device_window = window;
+
+    return hr;
+}
+
 static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3d_device *device,
         struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops)
 {
@@ -775,24 +812,17 @@ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3
         swapchain->swapchain_ops = &swapchain_gl_ops;
 
     window = desc->device_window ? desc->device_window : device->create_parms.focus_window;
+    if (FAILED(hr = wined3d_swapchain_state_init(&swapchain->state, desc, window, device->wined3d, adapter->ordinal)))
+        return hr;
 
     swapchain->device = device;
     swapchain->parent = parent;
     swapchain->parent_ops = parent_ops;
     swapchain->ref = 1;
     swapchain->win_handle = window;
-    swapchain->state.device_window = window;
     swapchain->swap_interval = WINED3D_SWAP_INTERVAL_DEFAULT;
     swapchain_set_max_frame_latency(swapchain, device);
 
-    if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d,
-            adapter->ordinal, &swapchain->original_mode, NULL)))
-    {
-        ERR("Failed to get current display mode, hr %#x.\n", hr);
-        goto err;
-    }
-    GetWindowRect(window, &swapchain->original_window_rect);
-
     GetClientRect(window, &client_rect);
     if (desc->windowed)
     {
@@ -811,8 +841,8 @@ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3
 
         if (desc->backbuffer_format == WINED3DFMT_UNKNOWN)
         {
-            desc->backbuffer_format = swapchain->original_mode.format_id;
-            TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->original_mode.format_id));
+            desc->backbuffer_format = swapchain->state.original_mode.format_id;
+            TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->state.original_mode.format_id));
         }
     }
     else
@@ -863,30 +893,16 @@ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3
     /* MSDN says we're only allowed a single fullscreen swapchain per device,
      * so we should really check to see if there is a fullscreen swapchain
      * already. Does a single head count as full screen? */
-    if (!desc->windowed)
+    if (!desc->windowed && desc->flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH)
     {
-        if (desc->flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH)
-        {
-            /* Change the display settings */
-            swapchain->d3d_mode.width = desc->backbuffer_width;
-            swapchain->d3d_mode.height = desc->backbuffer_height;
-            swapchain->d3d_mode.format_id = adapter_format_from_backbuffer_format(swapchain,
-                    desc->backbuffer_format);
-            swapchain->d3d_mode.refresh_rate = desc->refresh_rate;
-            swapchain->d3d_mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
-
-            if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d,
-                    adapter->ordinal, &swapchain->d3d_mode)))
-            {
-                WARN("Failed to set display mode, hr %#x.\n", hr);
-                goto err;
-            }
-            displaymode_set = TRUE;
-        }
-        else
+        /* Change the display settings */
+        if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d,
+                adapter->ordinal, &swapchain->state.d3d_mode)))
         {
-            swapchain->d3d_mode = swapchain->original_mode;
+            WARN("Failed to set display mode, hr %#x.\n", hr);
+            goto err;
         }
+        displaymode_set = TRUE;
     }
 
     if (swapchain->state.desc.backbuffer_count > 0)
@@ -963,7 +979,7 @@ err:
     if (displaymode_set)
     {
         if (FAILED(wined3d_set_adapter_display_mode(device->wined3d,
-                adapter->ordinal, &swapchain->original_mode)))
+                adapter->ordinal, &swapchain->state.original_mode)))
             ERR("Failed to restore display mode.\n");
         ClipCursor(NULL);
     }
@@ -1184,7 +1200,7 @@ void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activa
         if (device->wined3d->flags & WINED3D_RESTORE_MODE_ON_ACTIVATE)
         {
             if (FAILED(wined3d_set_adapter_display_mode(device->wined3d,
-                    device->adapter->ordinal, &swapchain->d3d_mode)))
+                    device->adapter->ordinal, &swapchain->state.d3d_mode)))
                 ERR("Failed to set display mode.\n");
         }
 
@@ -1272,7 +1288,7 @@ HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapcha
     {
         if (!desc->windowed)
             return WINED3DERR_INVALIDCALL;
-        format_id = swapchain->original_mode.format_id;
+        format_id = swapchain->state.original_mode.format_id;
     }
 
     if (format_id != desc->backbuffer_format)
@@ -1500,15 +1516,15 @@ void wined3d_swapchain_state_restore_from_fullscreen(struct wined3d_swapchain_st
     state->exstyle = 0;
 }
 
-HRESULT CDECL wined3d_swapchain_set_fullscreen(struct wined3d_swapchain *swapchain,
-        const struct wined3d_swapchain_desc *swapchain_desc, const struct wined3d_display_mode *mode)
+HRESULT CDECL wined3d_swapchain_state_set_fullscreen(struct wined3d_swapchain_state *state,
+        const struct wined3d_swapchain_desc *swapchain_desc, struct wined3d *wined3d,
+        unsigned int adapter_idx, const struct wined3d_display_mode *mode)
 {
-    struct wined3d_swapchain_state *state = &swapchain->state;
-    struct wined3d_device *device = swapchain->device;
     struct wined3d_display_mode actual_mode;
     HRESULT hr;
 
-    TRACE("swapchain %p, desc %p, mode %p.\n", swapchain, swapchain_desc, mode);
+    TRACE("state %p, swapchain_desc %p, wined3d %p, adapter_idx %u, mode %p.\n",
+            state, swapchain_desc, wined3d, adapter_idx, mode);
 
     if (state->desc.flags & WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH)
     {
@@ -1520,21 +1536,22 @@ HRESULT CDECL wined3d_swapchain_set_fullscreen(struct wined3d_swapchain *swapcha
         {
             if (!swapchain_desc->windowed)
             {
+                const struct wined3d_adapter *adapter = wined3d->adapters[adapter_idx];
+
                 actual_mode.width = swapchain_desc->backbuffer_width;
                 actual_mode.height = swapchain_desc->backbuffer_height;
                 actual_mode.refresh_rate = swapchain_desc->refresh_rate;
-                actual_mode.format_id = adapter_format_from_backbuffer_format(swapchain,
+                actual_mode.format_id = adapter_format_from_backbuffer_format(adapter,
                         swapchain_desc->backbuffer_format);
                 actual_mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
             }
             else
             {
-                actual_mode = swapchain->original_mode;
+                actual_mode = state->original_mode;
             }
         }
 
-        if (FAILED(hr = wined3d_swapchain_state_set_display_mode(state,
-                device->wined3d, device->adapter->ordinal, &actual_mode)))
+        if (FAILED(hr = wined3d_swapchain_state_set_display_mode(state, wined3d, adapter_idx, &actual_mode)))
             return hr;
     }
     else
@@ -1542,8 +1559,7 @@ HRESULT CDECL wined3d_swapchain_set_fullscreen(struct wined3d_swapchain *swapcha
         if (mode)
             WARN("WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH is not set, ignoring mode.\n");
 
-        if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, device->adapter->ordinal,
-                &actual_mode, NULL)))
+        if (FAILED(hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &actual_mode, NULL)))
         {
             ERR("Failed to get display mode, hr %#x.\n", hr);
             return WINED3DERR_INVALIDCALL;
@@ -1558,13 +1574,12 @@ HRESULT CDECL wined3d_swapchain_set_fullscreen(struct wined3d_swapchain *swapcha
         if (state->desc.windowed)
         {
             /* Switch from windowed to fullscreen */
-            if (FAILED(hr = wined3d_swapchain_state_setup_fullscreen(state,
-                    state->device_window, width, height)))
+            if (FAILED(hr = wined3d_swapchain_state_setup_fullscreen(state, state->device_window, width, height)))
                 return hr;
         }
         else
         {
-            HWND window = swapchain->state.device_window;
+            HWND window = state->device_window;
             BOOL filter;
 
             /* Fullscreen -> fullscreen mode change */
@@ -1573,14 +1588,14 @@ HRESULT CDECL wined3d_swapchain_set_fullscreen(struct wined3d_swapchain *swapcha
             ShowWindow(window, SW_SHOW);
             wined3d_filter_messages(window, filter);
         }
-        swapchain->d3d_mode = actual_mode;
+        state->d3d_mode = actual_mode;
     }
     else if (!state->desc.windowed)
     {
         /* Fullscreen -> windowed switch */
         RECT *window_rect = NULL;
         if (state->desc.flags & WINED3D_SWAPCHAIN_RESTORE_WINDOW_RECT)
-            window_rect = &swapchain->original_window_rect;
+            window_rect = &state->original_window_rect;
         wined3d_swapchain_state_restore_from_fullscreen(state, state->device_window, window_rect);
     }
 
@@ -1595,19 +1610,23 @@ void CDECL wined3d_swapchain_state_destroy(struct wined3d_swapchain_state *state
 }
 
 HRESULT CDECL wined3d_swapchain_state_create(const struct wined3d_swapchain_desc *desc,
-        HWND window, struct wined3d_swapchain_state **state)
+        HWND window, struct wined3d *wined3d, unsigned int adapter_idx, struct wined3d_swapchain_state **state)
 {
     struct wined3d_swapchain_state *s;
+    HRESULT hr;
+
+    TRACE("desc %p, window %p, wined3d %p, adapter_idx %u, state %p.\n",
+            desc, window, wined3d, adapter_idx, state);
 
     TRACE("desc %p, window %p, state %p.\n", desc, window, state);
 
     if (!(s = heap_alloc_zero(sizeof(*s))))
         return E_OUTOFMEMORY;
 
-    s->desc = *desc;
-    s->device_window = window;
+    if (FAILED(hr = wined3d_swapchain_state_init(s, desc, window, wined3d, adapter_idx)))
+        return hr;
 
     *state = s;
 
-    return WINED3D_OK;
+    return hr;
 }
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index 01e466e0147..edd4a70d979 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -273,14 +273,14 @@
 @ cdecl wined3d_swapchain_incref(ptr)
 @ cdecl wined3d_swapchain_present(ptr ptr ptr ptr long long)
 @ cdecl wined3d_swapchain_resize_buffers(ptr long long long long long long)
-@ cdecl wined3d_swapchain_set_fullscreen(ptr ptr ptr)
 @ cdecl wined3d_swapchain_set_gamma_ramp(ptr long ptr)
 @ cdecl wined3d_swapchain_set_palette(ptr ptr)
 @ cdecl wined3d_swapchain_set_window(ptr ptr)
 
-@ cdecl wined3d_swapchain_state_create(ptr ptr ptr)
+@ cdecl wined3d_swapchain_state_create(ptr ptr ptr long ptr)
 @ cdecl wined3d_swapchain_state_destroy(ptr)
 @ cdecl wined3d_swapchain_state_resize_target(ptr ptr long ptr)
+@ cdecl wined3d_swapchain_state_set_fullscreen(ptr ptr ptr long ptr)
 
 @ cdecl wined3d_texture_add_dirty_region(ptr long ptr)
 @ cdecl wined3d_texture_blt(ptr long ptr ptr long ptr long ptr long)
diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c
index 360d6d51962..132c9782def 100644
--- a/dlls/wined3d/wined3d_main.c
+++ b/dlls/wined3d/wined3d_main.c
@@ -565,7 +565,8 @@ static LRESULT CALLBACK wined3d_hook_proc(int code, WPARAM wparam, LPARAM lparam
 
             wined3d_swapchain_get_desc(swapchain, &swapchain_desc);
             swapchain_desc.windowed = !swapchain_desc.windowed;
-            wined3d_swapchain_set_fullscreen(swapchain, &swapchain_desc, NULL);
+            wined3d_swapchain_state_set_fullscreen(&swapchain->state, &swapchain_desc,
+                    swapchain->device->wined3d, swapchain->device->adapter->ordinal, NULL);
 
             wined3d_wndproc_mutex_unlock();
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 5ddf066878a..03a3afb85a8 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -4178,6 +4178,9 @@ struct wined3d_swapchain_state
 {
     struct wined3d_swapchain_desc desc;
 
+    struct wined3d_display_mode original_mode, d3d_mode;
+    RECT original_window_rect;
+
     /* Window styles to restore when switching fullscreen mode. */
     LONG style;
     LONG exstyle;
@@ -4206,8 +4209,6 @@ struct wined3d_swapchain
 
     struct wined3d_texture **back_buffers;
     struct wined3d_texture *front_buffer;
-    struct wined3d_display_mode original_mode, d3d_mode;
-    RECT original_window_rect;
     struct wined3d_gamma_ramp orig_gamma;
     BOOL render_to_fbo, reapply_mode;
     const struct wined3d_format *ds_format;
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index bae2cf86184..3e46c23c145 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2684,18 +2684,19 @@ HRESULT __cdecl wined3d_swapchain_present(struct wined3d_swapchain *swapchain, c
 HRESULT __cdecl wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count,
         unsigned int width, unsigned int height, enum wined3d_format_id format_id,
         enum wined3d_multisample_type multisample_type, unsigned int multisample_quality);
-HRESULT __cdecl wined3d_swapchain_set_fullscreen(struct wined3d_swapchain *swapchain,
-        const struct wined3d_swapchain_desc *desc, const struct wined3d_display_mode *mode);
 HRESULT __cdecl wined3d_swapchain_set_gamma_ramp(const struct wined3d_swapchain *swapchain,
         DWORD flags, const struct wined3d_gamma_ramp *ramp);
 void __cdecl wined3d_swapchain_set_palette(struct wined3d_swapchain *swapchain, struct wined3d_palette *palette);
 void __cdecl wined3d_swapchain_set_window(struct wined3d_swapchain *swapchain, HWND window);
 
 HRESULT __cdecl wined3d_swapchain_state_create(const struct wined3d_swapchain_desc *desc,
-        HWND window, struct wined3d_swapchain_state **state);
+        HWND window, struct wined3d *wined3d, unsigned int adapter_idx, struct wined3d_swapchain_state **state);
 void __cdecl wined3d_swapchain_state_destroy(struct wined3d_swapchain_state *state);
 HRESULT __cdecl wined3d_swapchain_state_resize_target(struct wined3d_swapchain_state *state,
         struct wined3d *wined3d, unsigned int adapter_idx, const struct wined3d_display_mode *mode);
+HRESULT __cdecl wined3d_swapchain_state_set_fullscreen(struct wined3d_swapchain_state *state,
+        const struct wined3d_swapchain_desc *desc, struct wined3d *wined3d,
+        unsigned int adapter_idx, const struct wined3d_display_mode *mode);
 
 HRESULT __cdecl wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
         UINT layer, const struct wined3d_box *dirty_region);
-- 
2.11.0




More information about the wine-devel mailing list