[PATCH] wined3d: Support multiple outputs.

Zhiyi Zhang zzhang at codeweavers.com
Mon Jan 25 08:22:19 CST 2021


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/d3d8/tests/device.c       |  5 +--
 dlls/d3d9/tests/device.c       |  5 +--
 dlls/dxgi/device.c             | 16 +-------
 dlls/dxgi/swapchain.c          | 20 +---------
 dlls/dxgi/tests/dxgi.c         | 26 +------------
 dlls/wined3d/directx.c         | 69 ++++++++++++++++++++++++++--------
 dlls/wined3d/wined3d_main.c    |  4 +-
 dlls/wined3d/wined3d_private.h |  2 -
 8 files changed, 62 insertions(+), 85 deletions(-)

diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c
index ffd940067e8..4eb1ab65e72 100644
--- a/dlls/d3d8/tests/device.c
+++ b/dlls/d3d8/tests/device.c
@@ -10455,9 +10455,8 @@ static void test_multi_adapter(void)
     }
 
     adapter_count = IDirect3D8_GetAdapterCount(d3d);
-    todo_wine_if(expected_adapter_count > 1)
-        ok(adapter_count == expected_adapter_count, "Got unexpected adapter count %u, expected %u.\n",
-                adapter_count, expected_adapter_count);
+    ok(adapter_count == expected_adapter_count, "Got unexpected adapter count %u, expected %u.\n",
+            adapter_count, expected_adapter_count);
 
     for (i = 0; i < adapter_count; ++i)
     {
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index ef8d9a34e25..3ef9361886d 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -14149,9 +14149,8 @@ static void test_multi_adapter(void)
     }
 
     adapter_count = IDirect3D9_GetAdapterCount(d3d);
-    todo_wine_if(expected_adapter_count > 1)
-        ok(adapter_count == expected_adapter_count, "Got unexpected adapter count %u, expected %u.\n",
-                adapter_count, expected_adapter_count);
+    ok(adapter_count == expected_adapter_count, "Got unexpected adapter count %u, expected %u.\n",
+            adapter_count, expected_adapter_count);
 
     for (i = 0; i < adapter_count; ++i)
     {
diff --git a/dlls/dxgi/device.c b/dlls/dxgi/device.c
index 5f0c40f2e47..74260f9b769 100644
--- a/dlls/dxgi/device.c
+++ b/dlls/dxgi/device.c
@@ -429,7 +429,6 @@ static HRESULT STDMETHODCALLTYPE dxgi_swapchain_factory_create_swapchain(IWineDX
     struct wined3d_swapchain_desc wined3d_desc;
     struct IDXGIOutput *containing_output;
     struct d3d11_swapchain *object;
-    struct IDXGIAdapter *adapter;
     HRESULT hr;
 
     TRACE("iface %p, factory %p, window %p, desc %p, fullscreen_desc %p, output %p, swapchain %p.\n",
@@ -438,20 +437,7 @@ static HRESULT STDMETHODCALLTYPE dxgi_swapchain_factory_create_swapchain(IWineDX
     if (FAILED(hr = dxgi_get_output_from_window(factory, window, &containing_output)))
     {
         WARN("Failed to get output from window %p, hr %#x.\n", window, hr);
-
-        /* FIXME: As wined3d only supports one output currently, even if a window is on a
-         * non-primary output, the swapchain will use the primary output. Keep this behaviour
-         * until all outputs are correctly enumerated. Otherwise it will create a regression
-         * for applications that specify a device window on a non-primary output */
-        if (FAILED(hr = IDXGIFactory_EnumAdapters(factory, 0, &adapter)))
-            return hr;
-
-        hr = IDXGIAdapter_EnumOutputs(adapter, 0, &containing_output);
-        IDXGIAdapter_Release(adapter);
-        if (FAILED(hr))
-            return hr;
-
-        FIXME("Using the primary output for the device window that is on a non-primary output.\n");
+        return hr;
     }
 
     hr = wined3d_swapchain_desc_from_dxgi(&wined3d_desc, containing_output, window, desc,
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 0f335a71cb7..82e5fbf811d 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -3000,9 +3000,7 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
     VkFenceCreateInfo fence_desc;
     uint32_t queue_family_index;
     VkSurfaceKHR vk_surface;
-    IUnknown *device_parent;
     VkInstance vk_instance;
-    IDXGIAdapter *adapter;
     IDXGIOutput *output;
     VkBool32 supported;
     VkDevice vk_device;
@@ -3043,27 +3041,11 @@ 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;
-
     if (FAILED(hr = dxgi_get_output_from_window((IDXGIFactory *)factory, window, &output)))
     {
         WARN("Failed to get output from window %p, hr %#x.\n", window, hr);
-
-        /* FIXME: As wined3d only supports one output currently, even if a window is on a
-         * non-primary output, the swapchain will use the primary output. Keep this behaviour
-         * until all outputs are correctly enumerated. Otherwise it will create a regression
-         * for applications that specify a device window on a non-primary output */
-        if (FAILED(hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output)))
-        {
-            IDXGIAdapter_Release(adapter);
-            return hr;
-        }
-
-        FIXME("Using the primary output for the device window that is on a non-primary output.\n");
+        return hr;
     }
-    IDXGIAdapter_Release(adapter);
 
     hr = wined3d_swapchain_desc_from_dxgi(&wined3d_desc, output, window, swapchain_desc,
             fullscreen_desc);
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 53d768d1a36..2d8826fde8e 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -2178,22 +2178,6 @@ done:
     DestroyWindow(creation_desc.OutputWindow);
 }
 
-static HMONITOR get_primary_if_right_side_secondary(const DXGI_OUTPUT_DESC *output_desc)
-{
-    HMONITOR primary, secondary;
-    MONITORINFO mi;
-    POINT pt = {0, 0};
-
-    primary = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
-    pt.x = output_desc->DesktopCoordinates.right;
-    secondary = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
-    mi.cbSize = sizeof(mi);
-    if (secondary && secondary != primary
-            && GetMonitorInfoW(primary, &mi) && (mi.dwFlags & MONITORINFOF_PRIMARY))
-        return primary;
-    return NULL;
-}
-
 static void test_get_containing_output(IUnknown *device, BOOL is_d3d12)
 {
     unsigned int adapter_idx, output_idx, output_count;
@@ -2207,7 +2191,6 @@ static void test_get_containing_output(IUnknown *device, BOOL is_d3d12)
     POINT points[4 * 16];
     unsigned int i, j;
     HMONITOR monitor;
-    HMONITOR primary;
     BOOL fullscreen;
     ULONG refcount;
     HRESULT hr;
@@ -2287,8 +2270,6 @@ static void test_get_containing_output(IUnknown *device, BOOL is_d3d12)
             wine_dbgstr_rect(&output_desc.DesktopCoordinates),
             wine_dbgstr_rect(&monitor_info.rcMonitor));
 
-    primary = get_primary_if_right_side_secondary(&output_desc);
-
     for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter));
             ++adapter_idx)
     {
@@ -2379,8 +2360,6 @@ static void test_get_containing_output(IUnknown *device, BOOL is_d3d12)
                         output_idx, i);
 
                 hr = IDXGISwapChain_GetContainingOutput(swapchain, &output2);
-                /* Hack to prevent test failures with secondary on the right until multi-monitor support is improved. */
-                todo_wine_if(primary && monitor != primary)
                 ok(hr == S_OK || broken(hr == DXGI_ERROR_UNSUPPORTED),
                         "Adapter %u output %u point %u: Failed to get containing output, hr %#x.\n",
                         adapter_idx, output_idx, i, hr);
@@ -5652,9 +5631,8 @@ done:
     IDXGIFactory_Release(factory);
 
     expected_output_count = GetSystemMetrics(SM_CMONITORS);
-    todo_wine_if(expected_output_count > 1)
-        ok(output_count == expected_output_count, "Expect output count %d, got %d\n",
-                expected_output_count, output_count);
+    ok(output_count == expected_output_count, "Expect output count %d, got %d\n",
+            expected_output_count, output_count);
 }
 
 struct message
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 2764b113065..040a9f81083 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -140,6 +140,7 @@ static HRESULT wined3d_output_init(struct wined3d_output *output, unsigned int o
     output->ordinal = ordinal;
     lstrcpyW(output->device_name, device_name);
     output->adapter = adapter;
+    output->screen_format = WINED3DFMT_UNKNOWN;
     output->kmt_adapter = open_adapter_desc.hAdapter;
     output->kmt_device = create_device_desc.hDevice;
     output->vidpn_source_id = open_adapter_desc.VidPnSourceId;
@@ -3105,16 +3106,46 @@ static struct wined3d_adapter *wined3d_adapter_no3d_create(unsigned int ordinal,
     return adapter;
 }
 
+static BOOL wined3d_adapter_create_output(struct wined3d_adapter *adapter, const WCHAR *output_name)
+{
+    struct wined3d_output *outputs;
+    HRESULT hr;
+
+    if (!adapter->outputs && !(adapter->outputs = heap_calloc(1, sizeof(*adapter->outputs))))
+    {
+        return FALSE;
+    }
+    else
+    {
+        if (!(outputs = heap_realloc(adapter->outputs,
+                sizeof(*adapter->outputs) * (adapter->output_count + 1))))
+            return FALSE;
+
+        adapter->outputs = outputs;
+    }
+
+    if (FAILED(hr = wined3d_output_init(&adapter->outputs[adapter->output_count],
+            adapter->output_count, adapter, output_name)))
+    {
+        ERR("Failed to initialise output %s, hr %#x.\n", wine_dbgstr_w(output_name), hr);
+        return FALSE;
+    }
+
+    ++adapter->output_count;
+    TRACE("Initialised output %s.\n", wine_dbgstr_w(output_name));
+    return TRUE;
+}
+
 BOOL wined3d_adapter_init(struct wined3d_adapter *adapter, unsigned int ordinal, const LUID *luid,
         const struct wined3d_adapter_ops *adapter_ops)
 {
+    unsigned int output_idx = 0, primary_idx = 0;
     DISPLAY_DEVICEW display_device;
-    unsigned int output_idx;
     BOOL ret = FALSE;
-    HRESULT hr;
 
     adapter->ordinal = ordinal;
     adapter->output_count = 0;
+    adapter->outputs = NULL;
 
     if (luid)
     {
@@ -3132,23 +3163,29 @@ BOOL wined3d_adapter_init(struct wined3d_adapter *adapter, unsigned int ordinal,
     TRACE("adapter %p LUID %08x:%08x.\n", adapter, adapter->luid.HighPart, adapter->luid.LowPart);
 
     display_device.cb = sizeof(display_device);
-    EnumDisplayDevicesW(NULL, ordinal, &display_device, 0);
-    TRACE("Display device: %s.\n", debugstr_w(display_device.DeviceName));
-    strcpyW(adapter->device_name, display_device.DeviceName);
-
-    if (!(adapter->outputs = heap_calloc(1, sizeof(*adapter->outputs))))
+    while (EnumDisplayDevicesW(NULL, output_idx++, &display_device, 0))
     {
-        ERR("Failed to allocate outputs.\n");
-        return FALSE;
-    }
+        /* Detached outputs are not enumerated */
+        if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+            continue;
 
-    if (FAILED(hr = wined3d_output_init(&adapter->outputs[0], 0, adapter,
-            display_device.DeviceName)))
-    {
-        ERR("Failed to initialise output, hr %#x.\n", hr);
-        goto done;
+        if (display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
+            primary_idx = adapter->output_count;
+
+        if (!wined3d_adapter_create_output(adapter, display_device.DeviceName))
+            goto done;
+    }
+    TRACE("Initialised %d outputs for adapter %p.\n", adapter->output_count, adapter);
+
+    /* Make the primary output first */
+    if (primary_idx)
+    {
+        struct wined3d_output tmp = adapter->outputs[0];
+        adapter->outputs[0] = adapter->outputs[primary_idx];
+        adapter->outputs[0].ordinal = 0;
+        adapter->outputs[primary_idx] = tmp;
+        adapter->outputs[primary_idx].ordinal = primary_idx;
     }
-    adapter->output_count = 1;
 
     memset(&adapter->driver_uuid, 0, sizeof(adapter->driver_uuid));
     memset(&adapter->device_uuid, 0, sizeof(adapter->device_uuid));
diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c
index 5ad390d9f56..293359714c3 100644
--- a/dlls/wined3d/wined3d_main.c
+++ b/dlls/wined3d/wined3d_main.c
@@ -497,9 +497,7 @@ static struct wined3d_output * wined3d_get_output_from_window(const struct wined
         }
     }
 
-    /* Because wined3d only supports one output right now. A window can be on non-primary outputs
-     * and thus fails to get its correct output. In this case, return the primary output for now */
-    return &wined3d->adapters[0]->outputs[0];
+    return NULL;
 }
 
 static struct wined3d_wndproc *wined3d_find_wndproc(HWND window, struct wined3d *wined3d)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b3934f0d8e4..119ce3af033 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3368,8 +3368,6 @@ struct wined3d_adapter
     GUID device_uuid;
     LUID luid;
 
-    WCHAR device_name[CCHDEVICENAME]; /* for use with e.g. ChangeDisplaySettings() */
-
     void *formats;
     size_t format_size;
 
-- 
2.27.0



More information about the wine-devel mailing list