[PATCH 1/7] user32/tests: Add DisplayConfigSetDeviceInfo() tests.

Zhiyi Zhang zzhang at codeweavers.com
Wed Sep 1 01:37:21 CDT 2021


Test that DisplayConfigSetDeviceInfo() can be used for getting and setting display DPI.

Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/user32/tests/monitor.c | 132 +++++++++++++++++++++++++++++++++---
 include/wingdi.h            |  51 ++++++++++----
 2 files changed, 161 insertions(+), 22 deletions(-)

diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index dfb57d3e2c2..cee7b629cd7 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -19,34 +19,49 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+
 #include "wine/test.h"
 #include "winbase.h"
 #include "wingdi.h"
 #include "winuser.h"
 #include "winreg.h"
+#include "winternl.h"
+#include "ddk/d3dkmthk.h"
 #include "wine/heap.h"
 #include <stdio.h>
 
-static HMODULE hdll;
 static LONG (WINAPI *pGetDisplayConfigBufferSizes)(UINT32,UINT32*,UINT32*);
+static BOOL (WINAPI *pGetDpiForMonitorInternal)(HMONITOR,UINT,UINT*,UINT*);
 static LONG (WINAPI *pQueryDisplayConfig)(UINT32,UINT32*,DISPLAYCONFIG_PATH_INFO*,UINT32*,
                                           DISPLAYCONFIG_MODE_INFO*,DISPLAYCONFIG_TOPOLOGY_ID*);
 static LONG (WINAPI *pDisplayConfigGetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER*);
+static LONG (WINAPI *pDisplayConfigSetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER*);
 static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
 
+static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER*);
+static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME*);
+
 static void init_function_pointers(void)
 {
-    hdll = GetModuleHandleA("user32.dll");
+    HMODULE user32 = GetModuleHandleA("user32.dll");
+    HMODULE gdi32 = GetModuleHandleA("gdi32.dll");
 
-#define GET_PROC(func) \
-    p ## func = (void*)GetProcAddress(hdll, #func); \
-    if(!p ## func) \
-      trace("GetProcAddress(%s) failed\n", #func);
+#define GET_PROC(module, func)                       \
+    p##func = (void *)GetProcAddress(module, #func); \
+    if (!p##func)                                    \
+        trace("GetProcAddress(%s, %s) failed.\n", #module, #func);
 
-    GET_PROC(GetDisplayConfigBufferSizes)
-    GET_PROC(QueryDisplayConfig)
-    GET_PROC(DisplayConfigGetDeviceInfo)
-    GET_PROC(SetThreadDpiAwarenessContext)
+    GET_PROC(user32, GetDisplayConfigBufferSizes)
+    GET_PROC(user32, GetDpiForMonitorInternal)
+    GET_PROC(user32, QueryDisplayConfig)
+    GET_PROC(user32, DisplayConfigGetDeviceInfo)
+    GET_PROC(user32, DisplayConfigSetDeviceInfo)
+    GET_PROC(user32, SetThreadDpiAwarenessContext)
+
+    GET_PROC(gdi32, D3DKMTCloseAdapter)
+    GET_PROC(gdi32, D3DKMTOpenAdapterFromGdiDisplayName)
 
 #undef GET_PROC
 }
@@ -68,6 +83,23 @@ static void flush_events(void)
     }
 }
 
+static unsigned int get_primary_dpi(void)
+{
+    DPI_AWARENESS_CONTEXT old_context;
+    UINT dpi_x = 0, dpi_y = 0;
+    POINT point = {0, 0};
+    HMONITOR monitor;
+
+    if (!pSetThreadDpiAwarenessContext || !pGetDpiForMonitorInternal)
+        return 0;
+
+    old_context = pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
+    monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
+    pGetDpiForMonitorInternal(monitor, 0, &dpi_x, &dpi_y);
+    pSetThreadDpiAwarenessContext(old_context);
+    return dpi_y;
+}
+
 static int get_bitmap_stride(int width, int bpp)
 {
     return ((width * bpp + 15) >> 3) & ~1;
@@ -1959,6 +1991,85 @@ static void test_display_config(void)
     test_DisplayConfigGetDeviceInfo();
 }
 
+static void test_DisplayConfigSetDeviceInfo(void)
+{
+    static const unsigned int scales[] = {100, 125, 150, 175, 200, 225, 250, 300, 350, 400, 450, 500};
+    int current_scale, current_scale_idx, recommended_scale_idx, step, dpi, old_dpi;
+    D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
+    DISPLAYCONFIG_GET_SOURCE_DPI_SCALE get_scale_req;
+    DISPLAYCONFIG_SET_SOURCE_DPI_SCALE set_scale_req;
+    D3DKMT_CLOSEADAPTER close_adapter_desc;
+    NTSTATUS status;
+    LONG ret;
+
+#define CHECK_FUNC(func)                       \
+    if (!p##func)                              \
+    {                                          \
+        skip("%s() is unavailable.\n", #func); \
+        return;                                \
+    }
+
+    CHECK_FUNC(D3DKMTCloseAdapter)
+    CHECK_FUNC(D3DKMTOpenAdapterFromGdiDisplayName)
+    CHECK_FUNC(DisplayConfigGetDeviceInfo)
+    CHECK_FUNC(DisplayConfigSetDeviceInfo)
+    CHECK_FUNC(GetDpiForMonitorInternal)
+    CHECK_FUNC(SetThreadDpiAwarenessContext)
+
+#undef CHECK_FUNC
+
+    lstrcpyW(open_adapter_gdi_desc.DeviceName, L"\\\\.\\DISPLAY1");
+    status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
+    ok(status == STATUS_SUCCESS, "D3DKMTOpenAdapterFromGdiDisplayName failed, status %#x.\n", status);
+
+    get_scale_req.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_DPI_SCALE;
+    get_scale_req.header.size = sizeof(get_scale_req);
+    get_scale_req.header.adapterId = open_adapter_gdi_desc.AdapterLuid;
+    get_scale_req.header.id = open_adapter_gdi_desc.VidPnSourceId;
+    ret = pDisplayConfigGetDeviceInfo(&get_scale_req.header);
+    if (ret != NO_ERROR)
+    {
+        skip("DisplayConfigGetDeviceInfo failed, returned %d.\n", ret);
+        goto failed;
+    }
+
+    dpi = get_primary_dpi();
+    old_dpi = dpi;
+    current_scale = dpi * 100 / 96;
+    for (current_scale_idx = 0; current_scale_idx < ARRAY_SIZE(scales); ++current_scale_idx)
+    {
+        if (scales[current_scale_idx] == current_scale)
+            break;
+    }
+    ok(scales[current_scale_idx] == current_scale, "Failed to find current scale.\n");
+    recommended_scale_idx = current_scale_idx - get_scale_req.curRelativeScaleStep;
+
+    set_scale_req.header.type = DISPLAYCONFIG_DEVICE_INFO_SET_SOURCE_DPI_SCALE;
+    set_scale_req.header.size = sizeof(set_scale_req);
+    set_scale_req.header.adapterId = open_adapter_gdi_desc.AdapterLuid;
+    set_scale_req.header.id = open_adapter_gdi_desc.VidPnSourceId;
+    for (step = get_scale_req.minRelativeScaleStep; step <= get_scale_req.maxRelativeScaleStep; ++step)
+    {
+        set_scale_req.relativeScaleStep = step;
+        ret = pDisplayConfigSetDeviceInfo(&set_scale_req.header);
+        ok(ret == NO_ERROR, "DisplayConfigSetDeviceInfo failed, returned %d.\n", ret);
+
+        dpi = scales[step + recommended_scale_idx] * 96 / 100;
+        ok(dpi == get_primary_dpi(), "Expected %d, got %d.\n", get_primary_dpi(), dpi);
+    }
+
+    /* Restore to the original scale */
+    set_scale_req.relativeScaleStep = get_scale_req.curRelativeScaleStep;
+    ret = pDisplayConfigSetDeviceInfo(&set_scale_req.header);
+    ok(ret == NO_ERROR, "DisplayConfigSetDeviceInfo failed, returned %d.\n", ret);
+    ok(old_dpi == get_primary_dpi(), "Expected %d, got %d.\n", get_primary_dpi(), old_dpi);
+
+failed:
+    close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+    status = pD3DKMTCloseAdapter(&close_adapter_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+}
+
 static BOOL CALLBACK test_handle_proc(HMONITOR full_monitor, HDC hdc, LPRECT rect, LPARAM lparam)
 {
     MONITORINFO monitor_info = {sizeof(monitor_info)};
@@ -2283,6 +2394,7 @@ START_TEST(monitor)
     init_function_pointers();
     test_enumdisplaydevices();
     test_ChangeDisplaySettingsEx();
+    test_DisplayConfigSetDeviceInfo();
     test_EnumDisplayMonitors();
     test_monitors();
     test_work_area();
diff --git a/include/wingdi.h b/include/wingdi.h
index c10d7518337..7220aff089b 100644
--- a/include/wingdi.h
+++ b/include/wingdi.h
@@ -3286,18 +3286,20 @@ typedef struct _RGNDATA {
 typedef BOOL (CALLBACK *ABORTPROC)(HDC, INT);
 
 typedef enum {
-    DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME                = 1,
-    DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME                = 2,
-    DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE      = 3,
-    DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME               = 4,
-    DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE         = 5,
-    DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE           = 6,
-    DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
-    DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
-    DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO        = 9,
-    DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE       = 10,
-    DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL            = 11,
-    DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32                   = 0xffffffff
+    DISPLAYCONFIG_DEVICE_INFO_SET_SOURCE_DPI_SCALE           = (int)-4,
+    DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_DPI_SCALE           = (int)-3,
+    DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME                = (int)1,
+    DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME                = (int)2,
+    DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE      = (int)3,
+    DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME               = (int)4,
+    DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE         = (int)5,
+    DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE           = (int)6,
+    DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = (int)7,
+    DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = (int)8,
+    DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO        = (int)9,
+    DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE       = (int)10,
+    DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL            = (int)11,
+    DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32                   = (int)0xffffffff
 } DISPLAYCONFIG_DEVICE_INFO_TYPE;
 
 typedef struct DISPLAYCONFIG_DEVICE_INFO_HEADER {
@@ -3638,6 +3640,31 @@ typedef struct DISPLAYCONFIG_SDR_WHITE_LEVEL {
     ULONG                            SDRWhiteLevel;
 } DISPLAYCONFIG_SDR_WHITE_LEVEL;
 
+/* Scale steps are relative to the recommended scale. For example:
+ * Scale : 100% 125% 150% 175% 200% 225% 250% 300% 350% 400% 450% 500%
+ * DPI   : 96   120  144  168  192  216  240  288  336  384  432  480
+ *         ^         ^         ^                             ^
+ *         |         |         Recommended scale, step is 0. |
+ *         |         Current scale, step is -2.              Max scale step is 6.
+ *         Minimum scale, step is -4.
+ *
+ * The scale values can be found in the display settings drop-down. The algorithm to calculate the
+ * recommended scale is unclear.
+ */
+typedef struct DISPLAYCONFIG_GET_SOURCE_DPI_SCALE
+{
+    DISPLAYCONFIG_DEVICE_INFO_HEADER header;
+    int minRelativeScaleStep;   /* Minimum scale step relative to the recommended scale */
+    int curRelativeScaleStep;   /* Current scale step relative to the recommended scale */
+    int maxRelativeScaleStep;   /* Maximum scale step relative to the recommended scale */
+} DISPLAYCONFIG_GET_SOURCE_DPI_SCALE;
+
+typedef struct DISPLAYCONFIG_SET_SOURCE_DPI_SCALE
+{
+    DISPLAYCONFIG_DEVICE_INFO_HEADER header;
+    int relativeScaleStep;      /* Target scale step relative to the recommended scale */
+} DISPLAYCONFIG_SET_SOURCE_DPI_SCALE;
+
 #define DISPLAYCONFIG_PATH_MODE_IDX_INVALID             0xffffffff
 #define DISPLAYCONFIG_PATH_TARGET_MODE_IDX_INVALID      0xffff
 #define DISPLAYCONFIG_PATH_DESKTOP_IMAGE_IDX_INVALID    0xffff
-- 
2.30.2




More information about the wine-devel mailing list