[PATCH 3/6] dxgi: Handle creation and cleanup of D3D12 fullscreen swapchains.

Conor McCarthy cmccarthy at codeweavers.com
Mon Oct 7 23:13:51 CDT 2019


Signed-off-by: Conor McCarthy <cmccarthy at codeweavers.com>
---
 dlls/dxgi/swapchain.c | 89 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 83 insertions(+), 6 deletions(-)

diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index c76ad1d1..1787ced5 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -1877,6 +1877,10 @@ static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain)
 {
     const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
     void *vulkan_module = vk_funcs->vulkan_module;
+    struct dxgi_adapter *dxgi_adapter;
+    IUnknown *device_parent;
+    IDXGIAdapter *adapter;
+    HRESULT hr;
 
     d3d12_swapchain_destroy_buffers(swapchain, TRUE);
 
@@ -1885,6 +1889,18 @@ static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain)
 
     wined3d_private_store_cleanup(&swapchain->private_store);
 
+    device_parent = vkd3d_get_device_parent(swapchain->device);
+    if (SUCCEEDED(hr = IUnknown_QueryInterface(device_parent, &IID_IDXGIAdapter, (void **)&adapter)))
+    {
+        dxgi_adapter = unsafe_impl_from_IDXGIAdapter(adapter);
+        wined3d_swapchain_state_cleanup_fullscreen(swapchain->state, dxgi_adapter->factory->wined3d, dxgi_adapter->ordinal, NULL);
+        IDXGIAdapter_Release(adapter);
+    }
+    else
+    {
+        ERR("Failed to get adapter for fullscreen state cleanup, hr %#x.\n", hr);
+    }
+
     if (swapchain->vk_device)
     {
         vk_funcs->p_vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL);
@@ -2807,6 +2823,36 @@ static BOOL init_vk_funcs(struct dxgi_vk_funcs *dxgi, VkInstance vk_instance, Vk
     return TRUE;
 }
 
+static HRESULT d3d12_swapchain_desc_adjust_display_mode(HWND window, struct wined3d_swapchain_desc *wined3d_desc,
+        const struct dxgi_adapter *dxgi_adapter)
+{
+    struct wined3d_display_mode wined3d_mode;
+    HRESULT hr;
+
+    wined3d_mode.width = wined3d_desc->backbuffer_width;
+    wined3d_mode.height = wined3d_desc->backbuffer_height;
+    wined3d_mode.refresh_rate = wined3d_desc->refresh_rate;
+    wined3d_mode.format_id = wined3d_desc->backbuffer_format;
+    wined3d_mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
+
+    wined3d_mutex_lock();
+    hr = wined3d_find_closest_matching_adapter_mode(dxgi_adapter->factory->wined3d, dxgi_adapter->ordinal, &wined3d_mode);
+    wined3d_mutex_unlock();
+
+    if (SUCCEEDED(hr))
+    {
+        if (wined3d_desc->backbuffer_width != wined3d_mode.width || wined3d_desc->backbuffer_height != wined3d_mode.height)
+            TRACE("Adjusting resolution from (%ux%u) to (%ux%u).\n", wined3d_desc->backbuffer_width,
+                    wined3d_desc->backbuffer_height, wined3d_mode.width, wined3d_mode.height);
+        wined3d_desc->backbuffer_width = wined3d_mode.width;
+        wined3d_desc->backbuffer_height = wined3d_mode.height;
+        wined3d_desc->backbuffer_format = wined3d_mode.format_id;
+        wined3d_desc->refresh_rate = wined3d_mode.refresh_rate;
+    }
+
+    return hr;
+}
+
 static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGIFactory *factory,
         ID3D12Device *device, ID3D12CommandQueue *queue, HWND window,
         const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc)
@@ -2867,10 +2913,21 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
     IDXGIAdapter_Release(adapter);
     if (FAILED(hr = wined3d_swapchain_desc_from_dxgi(&wined3d_desc, window, swapchain_desc, fullscreen_desc)))
         return hr;
+
+    /* For fullscreen swapchains, D3D12 changes the swapchain size to match the mode resolution. */
+    if (!fullscreen_desc->Windowed && FAILED(hr = d3d12_swapchain_desc_adjust_display_mode(window,
+            &wined3d_desc, dxgi_adapter)))
+        ERR("Failed to adjust resolution for fullscreen swapchain, hr %#x.\n", hr);
+
+    wined3d_desc.windowed = TRUE;
     if (FAILED(hr = wined3d_swapchain_state_create(&wined3d_desc, window,
             dxgi_adapter->factory->wined3d, dxgi_adapter->ordinal, &swapchain->state)))
         return hr;
 
+    swapchain->desc.Width = wined3d_desc.backbuffer_width;
+    swapchain->desc.Height = wined3d_desc.backbuffer_height;
+    swapchain->desc.Format = dxgi_format_from_wined3dformat(wined3d_desc.backbuffer_format);
+
     if (swapchain_desc->BufferUsage && swapchain_desc->BufferUsage != DXGI_USAGE_RENDER_TARGET_OUTPUT)
         FIXME("Ignoring buffer usage %#x.\n", swapchain_desc->BufferUsage);
     if (swapchain_desc->Scaling != DXGI_SCALING_STRETCH)
@@ -2885,8 +2942,6 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
         FIXME("Unhandled scanline ordering %#x.\n", fullscreen_desc->ScanlineOrdering);
     if (fullscreen_desc->Scaling)
         FIXME("Unhandled mode scaling %#x.\n", fullscreen_desc->Scaling);
-    if (!fullscreen_desc->Windowed)
-        FIXME("Fullscreen not supported yet.\n");
 
     vk_instance = vkd3d_instance_get_vk_instance(vkd3d_instance_from_device(device));
     vk_physical_device = vkd3d_get_vk_physical_device(device);
@@ -2930,10 +2985,7 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
     ID3D12Device_AddRef(swapchain->device = device);
 
     if (FAILED(hr = d3d12_swapchain_create_vulkan_swapchain(swapchain)))
-    {
-        d3d12_swapchain_destroy(swapchain);
-        return hr;
-    }
+        goto cleanup;
 
     fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
     fence_desc.pNext = NULL;
@@ -2955,7 +3007,32 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
 
     IWineDXGIFactory_AddRef(swapchain->factory = factory);
 
+    if (!fullscreen_desc->Windowed)
+    {
+        if (FAILED(hr = IDXGISwapChain3_GetContainingOutput(&swapchain->IDXGISwapChain3_iface,
+                &swapchain->target)))
+        {
+            ERR("Failed to get target output for fullscreen swapchain, hr %#x.\n", hr);
+            goto cleanup;
+        }
+
+        wined3d_desc.windowed = FALSE;
+        wined3d_mutex_lock();
+        hr = dxgi_swapchain_set_fullscreen_state(swapchain->state, &wined3d_desc, swapchain->target);
+        wined3d_mutex_unlock();
+        if (FAILED(hr))
+        {
+            WARN("Failed to set fullscreen state, hr %#x.\n", hr);
+            IDXGIOutput_Release(swapchain->target);
+            goto cleanup;
+        }
+    }
+
     return S_OK;
+
+cleanup:
+    d3d12_swapchain_destroy(swapchain);
+    return hr;
 }
 
 HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window,
-- 
2.23.0




More information about the wine-devel mailing list