Implement QueryDisplayConfig() and the closely related GetDisplayConfigBufferSizes(). Thanks to Zhiyi Zhang for reviewing earlier versions of this patchset.
Brendan Shanks (6): include: Add d3dkmdt.h. user32/tests: Mark DisplayConfigGetDeviceInfo() tests returning success as todo_wine. user32: Implement GetDisplayConfigBufferSizes(). user32/tests: Test additional flag values with GetDisplayConfigBufferSizes(). user32: Implement QueryDisplayConfig(). user32/tests: Add more QueryDisplayConfig() tests.
dlls/user32/sysparams.c | 287 +++++++++++++++++++++++++++++++++++- dlls/user32/tests/monitor.c | 92 ++++++++++-- include/Makefile.in | 1 + include/d3dkmdt.h | 59 ++++++++ 4 files changed, 422 insertions(+), 17 deletions(-) create mode 100644 include/d3dkmdt.h
Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- include/Makefile.in | 1 + include/d3dkmdt.h | 59 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 include/d3dkmdt.h
diff --git a/include/Makefile.in b/include/Makefile.in index 90fb873f203..56c5220daf7 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -119,6 +119,7 @@ SOURCES = \ d3dcommon.idl \ d3dcompiler.h \ d3dhal.h \ + d3dkmdt.h \ d3drm.h \ d3drmdef.h \ d3drmobj.h \ diff --git a/include/d3dkmdt.h b/include/d3dkmdt.h new file mode 100644 index 00000000000..f47688cf401 --- /dev/null +++ b/include/d3dkmdt.h @@ -0,0 +1,59 @@ +/* + * Copyright 2020 Brendan Shanks for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_D3DKMDT_H +#define __WINE_D3DKMDT_H + +typedef enum _D3DKMDT_VIDEO_SIGNAL_STANDARD +{ + D3DKMDT_VSS_UNINITIALIZED = 0, + D3DKMDT_VSS_VESA_DMT = 1, + D3DKMDT_VSS_VESA_GTF = 2, + D3DKMDT_VSS_VESA_CVT = 3, + D3DKMDT_VSS_IBM = 4, + D3DKMDT_VSS_APPLE = 5, + D3DKMDT_VSS_NTSC_M = 6, + D3DKMDT_VSS_NTSC_J = 7, + D3DKMDT_VSS_NTSC_443 = 8, + D3DKMDT_VSS_PAL_B = 9, + D3DKMDT_VSS_PAL_B1 = 10, + D3DKMDT_VSS_PAL_G = 11, + D3DKMDT_VSS_PAL_H = 12, + D3DKMDT_VSS_PAL_I = 13, + D3DKMDT_VSS_PAL_D = 14, + D3DKMDT_VSS_PAL_N = 15, + D3DKMDT_VSS_PAL_NC = 16, + D3DKMDT_VSS_SECAM_B = 17, + D3DKMDT_VSS_SECAM_D = 18, + D3DKMDT_VSS_SECAM_G = 19, + D3DKMDT_VSS_SECAM_H = 20, + D3DKMDT_VSS_SECAM_K = 21, + D3DKMDT_VSS_SECAM_K1 = 22, + D3DKMDT_VSS_SECAM_L = 23, + D3DKMDT_VSS_SECAM_L1 = 24, + D3DKMDT_VSS_EIA_861 = 25, + D3DKMDT_VSS_EIA_861A = 26, + D3DKMDT_VSS_EIA_861B = 27, + D3DKMDT_VSS_PAL_K = 28, + D3DKMDT_VSS_PAL_K1 = 29, + D3DKMDT_VSS_PAL_L = 30, + D3DKMDT_VSS_PAL_M = 31, + D3DKMDT_VSS_OTHER = 255 +} D3DKMDT_VIDEO_SIGNAL_STANDARD; + +#endif /* __WINE_D3DKMDT_H */
Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- dlls/user32/tests/monitor.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index afde67cd034..e00c2bc6bd5 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -1280,6 +1280,7 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT
for (i = 0; i < paths; i++) { + todo_wine { source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; source_name.header.size = sizeof(source_name); source_name.header.adapterId = pi[i].sourceInfo.adapterId; @@ -1288,7 +1289,9 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT ret = pDisplayConfigGetDeviceInfo(&source_name.header); ok(!ret, "Expected 0, got %d\n", ret); ok(source_name.viewGdiDeviceName[0] != '\0', "Expected GDI device name, got empty string\n"); + }
+ todo_wine { target_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; target_name.header.size = sizeof(target_name); target_name.header.adapterId = pi[i].targetInfo.adapterId; @@ -1297,7 +1300,9 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT ret = pDisplayConfigGetDeviceInfo(&target_name.header); ok(!ret, "Expected 0, got %d\n", ret); ok(target_name.monitorDevicePath[0] != '\0', "Expected monitor device path, got empty string\n"); + }
+ todo_wine { preferred_mode.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE; preferred_mode.header.size = sizeof(preferred_mode); preferred_mode.header.adapterId = pi[i].targetInfo.adapterId; @@ -1307,7 +1312,9 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT ok(!ret, "Expected 0, got %d\n", ret); ok(preferred_mode.width > 0 && preferred_mode.height > 0, "Expected non-zero height/width, got %ux%u\n", preferred_mode.width, preferred_mode.height); + }
+ todo_wine { adapter_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME; adapter_name.header.size = sizeof(adapter_name); adapter_name.header.adapterId = pi[i].sourceInfo.adapterId; @@ -1315,6 +1322,7 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT ret = pDisplayConfigGetDeviceInfo(&adapter_name.header); ok(!ret, "Expected 0, got %d\n", ret); ok(adapter_name.adapterDevicePath[0] != '\0', "Expected adapter device path, got empty string\n"); + }
/* Check corresponding modes */ if (pi[i].sourceInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=74472
Your paranoid android.
=== w1064v1809_2scr (32 bit report) ===
user32: monitor.c:670: Test failed: Device \.\DISPLAY2 test 35 EnumDisplaySettingsA failed, error 0xdeadbeef monitor.c:670: Test failed: Device \.\DISPLAY2 test 35 expect dmFields to contain 0x7c00a0, got 0 monitor.c:670: Test failed: Device \.\DISPLAY2 test 35 expect dmBitsPerPel 32, got 0 monitor.c:670: Test failed: Device \.\DISPLAY2 test 35 expect dmPelsWidth 2048, got 0 monitor.c:670: Test failed: Device \.\DISPLAY2 test 35 expect dmPelsHeight 1536, got 0 monitor.c:670: Test failed: Device \.\DISPLAY2 test 35 expect dmPosition.x 1024, got 0 monitor.c:670: Test failed: Device \.\DISPLAY2 test 35 expect dmDisplayFrequency 64, got 0
Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- dlls/user32/sysparams.c | 48 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-)
diff --git a/dlls/user32/sysparams.c b/dlls/user32/sysparams.c index 768aeb5d4fb..402a8309ebf 100644 --- a/dlls/user32/sysparams.c +++ b/dlls/user32/sysparams.c @@ -4504,14 +4504,56 @@ BOOL WINAPI PhysicalToLogicalPoint( HWND hwnd, POINT *point ) */ LONG WINAPI GetDisplayConfigBufferSizes(UINT32 flags, UINT32 *num_path_info, UINT32 *num_mode_info) { - FIXME("(0x%x %p %p): stub\n", flags, num_path_info, num_mode_info); + LONG ret = ERROR_GEN_FAILURE; + HANDLE mutex; + HDEVINFO devinfo; + SP_DEVINFO_DATA device_data = {sizeof(device_data)}; + DWORD monitor_index = 0, state_flags, type; + + FIXME("(0x%x %p %p): semi-stub\n", flags, num_path_info, num_mode_info);
if (!num_path_info || !num_mode_info) return ERROR_INVALID_PARAMETER;
*num_path_info = 0; - *num_mode_info = 0; - return ERROR_NOT_SUPPORTED; + + if (flags != QDC_ALL_PATHS && + flags != QDC_ONLY_ACTIVE_PATHS && + flags != QDC_DATABASE_CURRENT) + return ERROR_INVALID_PARAMETER; + + if (flags != QDC_ONLY_ACTIVE_PATHS) + FIXME("only returning active paths\n"); + + wait_graphics_driver_ready(); + mutex = get_display_device_init_mutex(); + + /* Iterate through "targets"/monitors. + * Each target corresponds to a path, and each path references a source and a target mode. + */ + devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, DISPLAY, NULL, DIGCF_PRESENT); + if (devinfo == INVALID_HANDLE_VALUE) + goto done; + + while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data)) + { + /* Only count active monitors */ + if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, + &type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0)) + goto done; + + if (state_flags & DISPLAY_DEVICE_ACTIVE) + (*num_path_info)++; + } + + *num_mode_info = *num_path_info * 2; + ret = ERROR_SUCCESS; + TRACE("returning %u path(s) %u mode(s)\n", *num_path_info, *num_mode_info); + +done: + SetupDiDestroyDeviceInfoList(devinfo); + release_display_device_init_mutex(mutex); + return ret; }
/***********************************************************************
Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- dlls/user32/tests/monitor.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index e00c2bc6bd5..8b3e7236c7e 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -1126,15 +1126,6 @@ static void test_GetDisplayConfigBufferSizes(void) ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); ok(modes == 100, "got %u\n", modes);
- paths = modes = 0; - ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &paths, &modes); - if (!ret) - ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); - else - ok(ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); - - /* Invalid flags, non-zero invalid flags validation is version (or driver?) dependent, - it's unreliable to use in tests. */ ret = pGetDisplayConfigBufferSizes(0, NULL, NULL); ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
@@ -1148,10 +1139,38 @@ static void test_GetDisplayConfigBufferSizes(void) ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); ok(modes == 100, "got %u\n", modes);
+ /* Flag validation on Windows is driver-dependent */ paths = modes = 100; ret = pGetDisplayConfigBufferSizes(0, &paths, &modes); ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); ok((modes == 0 || modes == 100) && paths == 0, "got %u, %u\n", modes, paths); + + paths = modes = 100; + ret = pGetDisplayConfigBufferSizes(0xFF, &paths, &modes); + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); + ok((modes == 0 || modes == 100) && paths == 0, "got %u, %u\n", modes, paths); + + /* Test success */ + paths = modes = 0; + ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &paths, &modes); + if (!ret) + ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); + else + ok(ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); + + paths = modes = 0; + ret = pGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &paths, &modes); + if (!ret) + ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); + else + ok(ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); + + paths = modes = 0; + ret = pGetDisplayConfigBufferSizes(QDC_DATABASE_CURRENT, &paths, &modes); + if (!ret) + ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); + else + ok(ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); }
static BOOL CALLBACK test_EnumDisplayMonitors_normal_cb(HMONITOR monitor, HDC hdc, LPRECT rect,
Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- dlls/user32/sysparams.c | 239 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 236 insertions(+), 3 deletions(-)
diff --git a/dlls/user32/sysparams.c b/dlls/user32/sysparams.c index 402a8309ebf..8b2b3381dc3 100644 --- a/dlls/user32/sysparams.c +++ b/dlls/user32/sysparams.c @@ -40,6 +40,7 @@ #include "winerror.h"
#include "initguid.h" +#include "d3dkmdt.h" #include "devguid.h" #include "setupapi.h" #include "controls.h" @@ -249,6 +250,10 @@ static const WCHAR CSu[] = {'%','u',0}; static const WCHAR CSd[] = {'%','d',0}; static const WCHAR CSrgb[] = {'%','u',' ','%','u',' ','%','u',0};
+DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2); +DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_GPU_LUID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 1); +DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_OUTPUT_ID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 2); + /* Wine specific monitor properties */ DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2); DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCMONITOR, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 3); @@ -4556,6 +4561,129 @@ done: return ret; }
+static DISPLAYCONFIG_ROTATION get_dc_rotation(const DEVMODEW *devmode) +{ + if (devmode->dmFields & DM_DISPLAYORIENTATION) + return devmode->u1.s2.dmDisplayOrientation + 1; + else + return DISPLAYCONFIG_ROTATION_IDENTITY; +} + +static DISPLAYCONFIG_SCANLINE_ORDERING get_dc_scanline_ordering(const DEVMODEW *devmode) +{ + if (!(devmode->dmFields & DM_DISPLAYFLAGS)) + return DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED; + else if (devmode->u2.dmDisplayFlags & DM_INTERLACED) + return DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED; + else + return DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE; +} + +static DISPLAYCONFIG_PIXELFORMAT get_dc_pixelformat(DWORD dmBitsPerPel) +{ + if ((dmBitsPerPel == 8) || (dmBitsPerPel == 16) || + (dmBitsPerPel == 24) || (dmBitsPerPel == 32)) + return dmBitsPerPel / 8; + else + return DISPLAYCONFIG_PIXELFORMAT_NONGDI; +} + +static void set_mode_target_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid, UINT32 target_id, + UINT32 flags, const DEVMODEW *devmode) +{ + DISPLAYCONFIG_TARGET_MODE *mode = &(info->u.targetMode); + + info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_TARGET; + info->adapterId = *gpu_luid; + info->id = target_id; + + /* FIXME: Populate pixelRate/hSyncFreq/totalSize with real data */ + mode->targetVideoSignalInfo.pixelRate = devmode->dmDisplayFrequency * devmode->dmPelsWidth * devmode->dmPelsHeight; + mode->targetVideoSignalInfo.hSyncFreq.Numerator = devmode->dmDisplayFrequency * devmode->dmPelsWidth; + mode->targetVideoSignalInfo.hSyncFreq.Denominator = 1; + mode->targetVideoSignalInfo.vSyncFreq.Numerator = devmode->dmDisplayFrequency; + mode->targetVideoSignalInfo.vSyncFreq.Denominator = 1; + mode->targetVideoSignalInfo.activeSize.cx = devmode->dmPelsWidth; + mode->targetVideoSignalInfo.activeSize.cy = devmode->dmPelsHeight; + if (flags & QDC_DATABASE_CURRENT) + { + mode->targetVideoSignalInfo.totalSize.cx = 0; + mode->targetVideoSignalInfo.totalSize.cy = 0; + } + else + { + mode->targetVideoSignalInfo.totalSize.cx = devmode->dmPelsWidth; + mode->targetVideoSignalInfo.totalSize.cy = devmode->dmPelsHeight; + } + mode->targetVideoSignalInfo.u.videoStandard = D3DKMDT_VSS_OTHER; + mode->targetVideoSignalInfo.scanLineOrdering = get_dc_scanline_ordering(devmode); +} + +static void set_path_target_info(DISPLAYCONFIG_PATH_TARGET_INFO *info, const LUID *gpu_luid, + UINT32 target_id, UINT32 mode_index, const DEVMODEW *devmode) +{ + info->adapterId = *gpu_luid; + info->id = target_id; + info->u.modeInfoIdx = mode_index; + info->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL; + info->rotation = get_dc_rotation(devmode); + info->scaling = DISPLAYCONFIG_SCALING_IDENTITY; + info->refreshRate.Numerator = devmode->dmDisplayFrequency; + info->refreshRate.Denominator = 1; + info->scanLineOrdering = get_dc_scanline_ordering(devmode); + info->targetAvailable = TRUE; + info->statusFlags = DISPLAYCONFIG_TARGET_IN_USE; +} + +static void set_mode_source_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid, + UINT32 source_id, const DEVMODEW *devmode) +{ + DISPLAYCONFIG_SOURCE_MODE *mode = &(info->u.sourceMode); + + info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE; + info->adapterId = *gpu_luid; + info->id = source_id; + + mode->width = devmode->dmPelsWidth; + mode->height = devmode->dmPelsHeight; + mode->pixelFormat = get_dc_pixelformat(devmode->dmBitsPerPel); + if (devmode->dmFields & DM_POSITION) + { + mode->position = devmode->u1.s2.dmPosition; + } + else + { + mode->position.x = 0; + mode->position.y = 0; + } +} + +static void set_path_source_info(DISPLAYCONFIG_PATH_SOURCE_INFO *info, const LUID *gpu_luid, + UINT32 source_id, UINT32 mode_index) +{ + info->adapterId = *gpu_luid; + info->id = source_id; + info->u.modeInfoIdx = mode_index; + info->statusFlags = DISPLAYCONFIG_SOURCE_IN_USE; +} + +static BOOL source_mode_exists(const DISPLAYCONFIG_MODE_INFO *modeinfo, UINT32 num_modes, + UINT32 source_id, UINT32 *found_mode_index) +{ + UINT32 i; + + for (i = 0; i < num_modes; i++) + { + if (modeinfo[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE && + modeinfo[i].id == source_id) + { + *found_mode_index = i; + return TRUE; + } + } + return FALSE; +} + /*********************************************************************** * QueryDisplayConfig (USER32.@) */ @@ -4563,7 +4691,17 @@ LONG WINAPI QueryDisplayConfig(UINT32 flags, UINT32 *numpathelements, DISPLAYCON UINT32 *numinfoelements, DISPLAYCONFIG_MODE_INFO *modeinfo, DISPLAYCONFIG_TOPOLOGY_ID *topologyid) { - FIXME("(%08x %p %p %p %p %p)\n", flags, numpathelements, pathinfo, numinfoelements, modeinfo, topologyid); + LONG adapter_index, ret; + HANDLE mutex; + HDEVINFO devinfo; + SP_DEVINFO_DATA device_data = {sizeof(device_data)}; + DWORD monitor_index = 0, state_flags, type; + UINT32 output_id, source_mode_index, path_index = 0, mode_index = 0; + LUID gpu_luid; + WCHAR device_name[CCHDEVICENAME]; + DEVMODEW devmode; + + FIXME("(%08x %p %p %p %p %p): semi-stub\n", flags, numpathelements, pathinfo, numinfoelements, modeinfo, topologyid);
if (!numpathelements || !numinfoelements) return ERROR_INVALID_PARAMETER; @@ -4571,10 +4709,105 @@ LONG WINAPI QueryDisplayConfig(UINT32 flags, UINT32 *numpathelements, DISPLAYCON if (!*numpathelements || !*numinfoelements) return ERROR_INVALID_PARAMETER;
- if (!flags) + if (flags != QDC_ALL_PATHS && + flags != QDC_ONLY_ACTIVE_PATHS && + flags != QDC_DATABASE_CURRENT) + return ERROR_INVALID_PARAMETER; + + if (((flags == QDC_DATABASE_CURRENT) && !topologyid) || + ((flags != QDC_DATABASE_CURRENT) && topologyid)) return ERROR_INVALID_PARAMETER;
- return ERROR_NOT_SUPPORTED; + if (flags != QDC_ONLY_ACTIVE_PATHS) + FIXME("only returning active paths\n"); + + if (topologyid) + { + FIXME("setting toplogyid to DISPLAYCONFIG_TOPOLOGY_INTERNAL\n"); + *topologyid = DISPLAYCONFIG_TOPOLOGY_INTERNAL; + } + + wait_graphics_driver_ready(); + mutex = get_display_device_init_mutex(); + + /* Iterate through "targets"/monitors. + * Each target corresponds to a path, and each path corresponds to one or two unique modes. + */ + devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, DISPLAY, NULL, DIGCF_PRESENT); + if (devinfo == INVALID_HANDLE_VALUE) + { + ret = ERROR_GEN_FAILURE; + goto done; + } + + ret = ERROR_GEN_FAILURE; + while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data)) + { + /* Only count active monitors */ + if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, + &type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0)) + goto done; + if (!(state_flags & DISPLAY_DEVICE_ACTIVE)) + continue; + + if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID, + &type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0)) + goto done; + + if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_OUTPUT_ID, + &type, (BYTE *)&output_id, sizeof(output_id), NULL, 0)) + goto done; + + if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, + &type, (BYTE *)device_name, sizeof(device_name), NULL, 0)) + goto done; + + devmode.dmSize = sizeof(devmode); + if (!EnumDisplaySettingsW(device_name, ENUM_CURRENT_SETTINGS, &devmode)) + goto done; + + /* Extract the adapter index from device_name to use as the source ID */ + adapter_index = strtolW(device_name + ARRAY_SIZE(ADAPTER_PREFIX), NULL, 10); + adapter_index--; + + if (path_index == *numpathelements || mode_index == *numinfoelements) + { + ret = ERROR_INSUFFICIENT_BUFFER; + goto done; + } + + pathinfo[path_index].flags = DISPLAYCONFIG_PATH_ACTIVE; + set_mode_target_info(&modeinfo[mode_index], &gpu_luid, output_id, flags, &devmode); + set_path_target_info(&(pathinfo[path_index].targetInfo), &gpu_luid, output_id, mode_index, &devmode); + + mode_index++; + if (mode_index == *numinfoelements) + { + ret = ERROR_INSUFFICIENT_BUFFER; + goto done; + } + + /* Multiple targets can be driven by the same source, ensure a mode + * hasn't already been added for this source. + */ + if (!source_mode_exists(modeinfo, mode_index, adapter_index, &source_mode_index)) + { + set_mode_source_info(&modeinfo[mode_index], &gpu_luid, adapter_index, &devmode); + source_mode_index = mode_index; + mode_index++; + } + set_path_source_info(&(pathinfo[path_index].sourceInfo), &gpu_luid, adapter_index, source_mode_index); + path_index++; + } + + *numpathelements = path_index; + *numinfoelements = mode_index; + ret = ERROR_SUCCESS; + +done: + SetupDiDestroyDeviceInfoList(devinfo); + release_display_device_init_mutex(mutex); + return ret; }
/***********************************************************************
Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- dlls/user32/tests/monitor.c | 47 +++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index 8b3e7236c7e..f469111a26c 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -1288,7 +1288,8 @@ static void test_EnumDisplayMonitors(void) } }
-static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PATH_INFO *pi, UINT32 modes, const DISPLAYCONFIG_MODE_INFO *mi) +static void test_QueryDisplayConfig_result(UINT32 flags, + UINT32 paths, const DISPLAYCONFIG_PATH_INFO *pi, UINT32 modes, const DISPLAYCONFIG_MODE_INFO *mi) { UINT32 i; LONG ret; @@ -1385,6 +1386,24 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT "Expected LUID %08x:%08x, got %08x:%08x\n", pi[i].targetInfo.adapterId.HighPart, pi[i].targetInfo.adapterId.LowPart, mi[pi[i].targetInfo.modeInfoIdx].adapterId.HighPart, mi[pi[i].targetInfo.modeInfoIdx].adapterId.LowPart); + ok(mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.activeSize.cx > 0 && + mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.activeSize.cy > 0, + "Expected non-zero height/width, got %ux%u\n", + mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.activeSize.cx, + mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.activeSize.cy); + + if (flags == QDC_DATABASE_CURRENT) + ok(mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.totalSize.cx == 0 && + mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.totalSize.cy == 0, + "Expected zero height/width, got %ux%u\n", + mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.totalSize.cx, + mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.totalSize.cy); + else + ok(mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.totalSize.cx > 0 && + mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.totalSize.cy > 0, + "Expected non-zero height/width, got %ux%u\n", + mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.totalSize.cx, + mi[pi[i].targetInfo.modeInfoIdx].targetMode.targetVideoSignalInfo.totalSize.cy); } }
@@ -1393,6 +1412,7 @@ static void test_QueryDisplayConfig(void) UINT32 paths, modes; DISPLAYCONFIG_PATH_INFO pi[10]; DISPLAYCONFIG_MODE_INFO mi[20]; + DISPLAYCONFIG_TOPOLOGY_ID topologyid; LONG ret;
ret = pQueryDisplayConfig(QDC_ALL_PATHS, NULL, NULL, NULL, NULL, NULL); @@ -1435,6 +1455,18 @@ static void test_QueryDisplayConfig(void) ret = pQueryDisplayConfig(0, &paths, pi, &modes, mi, NULL); ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
+ paths = modes = 1; + ret = pQueryDisplayConfig(0xFF, &paths, pi, &modes, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); + + paths = modes = 1; + ret = pQueryDisplayConfig(QDC_DATABASE_CURRENT, &paths, pi, &modes, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); + + paths = modes = 1; + ret = pQueryDisplayConfig(QDC_ALL_PATHS, &paths, pi, &modes, mi, &topologyid); + ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); + /* Below this point, test functionality that requires a WDDM driver on Windows */ paths = modes = 1; memset(pi, 0xFF, sizeof(pi[0])); @@ -1458,7 +1490,18 @@ static void test_QueryDisplayConfig(void) ok(!ret, "got %d\n", ret); ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); if (!ret && paths > 0 && modes > 0) - test_QueryDisplayConfig_result(paths, pi, modes, mi); + test_QueryDisplayConfig_result(QDC_ONLY_ACTIVE_PATHS, paths, pi, modes, mi); + + paths = ARRAY_SIZE(pi); + modes = ARRAY_SIZE(mi); + memset(pi, 0xFF, sizeof(pi)); + memset(mi, 0xFF, sizeof(mi)); + topologyid = 0xFF; + ret = pQueryDisplayConfig(QDC_DATABASE_CURRENT, &paths, pi, &modes, mi, &topologyid); + ok(!ret, "got %d\n", ret); + ok(topologyid != 0xFF, "expected topologyid to be set, got %d\n", topologyid); + if (!ret && paths > 0 && modes > 0) + test_QueryDisplayConfig_result(QDC_DATABASE_CURRENT, paths, pi, modes, mi); }
static void test_DisplayConfigGetDeviceInfo(void)