Some games (Alan Wake 2 Remastered, Control, Silent Hill 2, S.T.A.L.K.E.R 2) check DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO) before attempting to use HDR. Add a semi-stub to return the typical status for a non-HDR monitor, along with typical status for an HDR-capable monitor when `gdi_monitor.hdr_enabled` is true. Then add support to winemac for detecting HDR-capable displays and returning that status in `gdi_monitor`.
From: Brendan Shanks bshanks@codeweavers.com
--- dlls/user32/tests/monitor.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index 206d9505705..db481029f32 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -1982,6 +1982,7 @@ static void test_QueryDisplayConfig_result(UINT32 flags, DISPLAYCONFIG_TARGET_DEVICE_NAME target_name; DISPLAYCONFIG_TARGET_PREFERRED_MODE preferred_mode; DISPLAYCONFIG_ADAPTER_NAME adapter_name; + DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO color_info; const DISPLAYCONFIG_DESKTOP_IMAGE_INFO *di;
for (i = 0; i < paths; i++) @@ -2033,6 +2034,14 @@ static void test_QueryDisplayConfig_result(UINT32 flags, ok(!ret, "Expected 0, got %ld\n", ret); ok(adapter_name.adapterDevicePath[0] != '\0', "Expected adapter device path, got empty string\n");
+ color_info.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO; + color_info.header.size = sizeof(color_info); + color_info.header.adapterId = pi[i].targetInfo.adapterId; + color_info.header.id = pi[i].targetInfo.id; + ret = pDisplayConfigGetDeviceInfo(&color_info.header); + todo_wine ok(!ret || broken(ret == ERROR_INVALID_PARAMETER) /* before Win10 1709 */, + "Expected 0, got %ld\n", ret); + /* Check corresponding modes */ if (flags & QDC_VIRTUAL_MODE_AWARE) { @@ -2287,6 +2296,7 @@ static void test_DisplayConfigGetDeviceInfo(void) DISPLAYCONFIG_TARGET_DEVICE_NAME target_name; DISPLAYCONFIG_TARGET_PREFERRED_MODE preferred_mode; DISPLAYCONFIG_ADAPTER_NAME adapter_name; + DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO color_info;
ret = pDisplayConfigGetDeviceInfo(NULL); ok(ret == ERROR_GEN_FAILURE, "got %ld\n", ret); @@ -2366,6 +2376,18 @@ static void test_DisplayConfigGetDeviceInfo(void) adapter_name.header.adapterId.HighPart = 0xFFFF; ret = pDisplayConfigGetDeviceInfo(&adapter_name.header); ok(ret == ERROR_GEN_FAILURE || ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); + + color_info.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO; + color_info.header.size = sizeof(color_info) - 1; + ret = pDisplayConfigGetDeviceInfo(&color_info.header); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + color_info.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO; + color_info.header.size = sizeof(color_info); + color_info.header.adapterId.LowPart = 0xFFFF; + color_info.header.adapterId.HighPart = 0xFFFF; + ret = pDisplayConfigGetDeviceInfo(&color_info.header); + ok(ret == ERROR_GEN_FAILURE || ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); }
static void test_display_config(void)
From: Brendan Shanks bshanks@codeweavers.com
--- dlls/user32/tests/monitor.c | 2 +- dlls/win32u/sysparams.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index db481029f32..69a46faba28 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -2039,7 +2039,7 @@ static void test_QueryDisplayConfig_result(UINT32 flags, color_info.header.adapterId = pi[i].targetInfo.adapterId; color_info.header.id = pi[i].targetInfo.id; ret = pDisplayConfigGetDeviceInfo(&color_info.header); - todo_wine ok(!ret || broken(ret == ERROR_INVALID_PARAMETER) /* before Win10 1709 */, + ok(!ret || broken(ret == ERROR_INVALID_PARAMETER) /* before Win10 1709 */, "Expected 0, got %ld\n", ret);
/* Check corresponding modes */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index e7e07c76638..92ac330847d 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -7767,11 +7767,42 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD unlock_display_devices(); return ret; } + case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO: + { + DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO *color_info = (DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO *)packet; + struct monitor *monitor; + + FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO semi-stub.\n" ); + + if (packet->size < sizeof(*color_info)) + return STATUS_INVALID_PARAMETER; + + if (!lock_display_devices( FALSE )) return STATUS_UNSUCCESSFUL; + + LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry) + { + if (color_info->header.id != monitor->output_id) continue; + if (memcmp( &color_info->header.adapterId, &monitor->source->gpu->luid, + sizeof(monitor->source->gpu->luid) )) + continue; + + color_info->advancedColorSupported = 0; + color_info->advancedColorEnabled = 0; + color_info->wideColorEnforced = 0; + color_info->advancedColorForceDisabled = 0; + color_info->colorEncoding = DISPLAYCONFIG_COLOR_ENCODING_RGB; + color_info->bitsPerColorChannel = 8; + ret = STATUS_SUCCESS; + break; + } + + unlock_display_devices(); + return ret; + } case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE: case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE: case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION: case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION: - case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO: case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE: case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL: default:
From: Brendan Shanks bshanks@codeweavers.com
--- dlls/win32u/sysparams.c | 37 ++++++++++++++++++++++++++++++++++--- include/wine/gdi_driver.h | 1 + 2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 92ac330847d..6987c47847c 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -64,6 +64,7 @@ static const char devpropkey_device_ispresentA[] = "Properties\{540B947E-8B40-4 static const char devpropkey_monitor_gpu_luidA[] = "Properties\{CA085853-16CE-48AA-B114-DE9C72334223}\0001"; static const char devpropkey_monitor_output_idA[] = "Properties\{CA085853-16CE-48AA-B114-DE9C72334223}\0002"; static const char wine_devpropkey_monitor_rcworkA[] = "Properties\{233a9ef3-afc4-4abd-b564-c32f21f1535b}\0004"; +static const char wine_devpropkey_monitor_hdr_enabledA[] = "Properties\{233a9ef3-afc4-4abd-b564-c32f21f1535b}\0006";
static const WCHAR linkedW[] = {'L','i','n','k','e','d',0}; static const WCHAR symbolic_link_valueW[] = @@ -155,6 +156,7 @@ struct monitor RECT rc_work; BOOL is_clone; struct edid_monitor_info edid_info; + BOOL hdr_enabled; };
static struct list gpus = LIST_INIT(gpus); @@ -755,6 +757,16 @@ static BOOL read_monitor_from_registry( struct monitor *monitor ) NtClose( subkey ); }
+ /* WINE_DEVPROPKEY_MONITOR_HDR_ENABLED */ + size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_hdr_enabledA, + value, sizeof(buffer) ); + if (size != sizeof(monitor->hdr_enabled)) + { + NtClose( hkey ); + return FALSE; + } + monitor->hdr_enabled = *(const BOOL *)value->Data; + NtClose( hkey ); return TRUE; } @@ -1928,6 +1940,14 @@ static BOOL write_monitor_to_registry( struct monitor *monitor, const BYTE *edid NtClose( subkey ); }
+ /* WINE_DEVPROPKEY_MONITOR_HDR_ENABLED */ + if ((subkey = reg_create_ascii_key( hkey, wine_devpropkey_monitor_hdr_enabledA, 0, NULL ))) + { + set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BOOLEAN, + &monitor->hdr_enabled, sizeof(monitor->hdr_enabled) ); + NtClose( subkey ); + } + NtClose( hkey );
@@ -1957,6 +1977,7 @@ static void add_monitor( const struct gdi_monitor *gdi_monitor, void *param ) monitor->id = source->monitor_count; monitor->output_id = ctx->monitor_count; monitor->rc_work = gdi_monitor->rc_work; + monitor->hdr_enabled = gdi_monitor->hdr_enabled;
TRACE( "%u %s %s\n", monitor->id, wine_dbgstr_rect(&gdi_monitor->rc_monitor), wine_dbgstr_rect(&gdi_monitor->rc_work) );
@@ -7786,12 +7807,22 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD sizeof(monitor->source->gpu->luid) )) continue;
- color_info->advancedColorSupported = 0; - color_info->advancedColorEnabled = 0; + if (monitor->hdr_enabled) + { + color_info->advancedColorSupported = 1; + color_info->advancedColorEnabled = 1; + color_info->bitsPerColorChannel = 10; + } + else + { + color_info->advancedColorSupported = 0; + color_info->advancedColorEnabled = 0; + color_info->bitsPerColorChannel = 8; + } color_info->wideColorEnforced = 0; color_info->advancedColorForceDisabled = 0; color_info->colorEncoding = DISPLAYCONFIG_COLOR_ENCODING_RGB; - color_info->bitsPerColorChannel = 8; + ret = STATUS_SUCCESS; break; } diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 1e13900489e..81932436963 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -342,6 +342,7 @@ struct gdi_monitor RECT rc_work; /* RcWork in MONITORINFO struct */ unsigned char *edid; /* Extended Device Identification Data */ UINT edid_len; + BOOL hdr_enabled; };
struct gdi_device_manager
From: Brendan Shanks bshanks@codeweavers.com
--- dlls/winemac.drv/cocoa_display.m | 5 +++++ dlls/winemac.drv/display.c | 1 + dlls/winemac.drv/macdrv_cocoa.h | 1 + 3 files changed, 7 insertions(+)
diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m index 372d89381f1..68820eb6c3c 100644 --- a/dlls/winemac.drv/cocoa_display.m +++ b/dlls/winemac.drv/cocoa_display.m @@ -654,6 +654,11 @@ int macdrv_get_monitors(CGDirectDisplayID adapter_id, struct macdrv_monitor** ne monitors[monitor_count].id = display_ids[i]; monitors[monitor_count].rc_monitor = convert_display_rect(screen.frame, primary_frame); monitors[monitor_count].rc_work = convert_display_rect(screen.visibleFrame, primary_frame); + monitors[monitor_count].hdr_enabled = false; +#if defined(MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15 + if (@available(macOS 10.15, *)) + monitors[monitor_count].hdr_enabled = (screen.maximumPotentialExtendedDynamicRangeColorComponentValue > 1.0) ? true : false; +#endif monitor_count++; break; } diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c index 8b012379b2e..39dcf35ff09 100644 --- a/dlls/winemac.drv/display.c +++ b/dlls/winemac.drv/display.c @@ -1093,6 +1093,7 @@ UINT macdrv_UpdateDisplayDevices(const struct gdi_device_manager *device_manager { .rc_monitor = rect_from_cgrect(monitor->rc_monitor), .rc_work = rect_from_cgrect(monitor->rc_work), + .hdr_enabled = monitor->hdr_enabled, }; device_manager->add_monitor( &gdi_monitor, param );
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 954acb0fc67..1f0e112ae06 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -253,6 +253,7 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point) CGRect rc_monitor; /* as RcWork in MONITORINFO struct after conversion by rect_from_cgrect */ CGRect rc_work; + bool hdr_enabled; };
extern int macdrv_set_display_mode(CGDirectDisplayID id, CGDisplayModeRef display_mode);
I forgot to mention, this is adapted from a Proton patch: https://github.com/ValveSoftware/wine/commit/e56b6f4b63eceea310099b99fd2e3d3...