We will need to inform wineserver of the available monitor physical/virtual rects and dpi in order for it to be able to correctly find windows from mouse input position, as well as for desktop clipping rectangles, so keep the monitors in a list until we've listed them all.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 72 +++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 35 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index f16934887a7..f42527a10a0 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -745,6 +745,41 @@ static void reg_empty_key( HKEY root, const char *key_name ) if (hkey != root) NtClose( hkey ); }
+static void clear_display_devices(void) +{ + struct source *source; + struct monitor *monitor; + struct gpu *gpu; + + if (list_head( &monitors ) == &virtual_monitor.entry) + { + list_init( &monitors ); + return; + } + + while (!list_empty( &monitors )) + { + monitor = LIST_ENTRY( list_head( &monitors ), struct monitor, entry ); + if (monitor->source) source_release( monitor->source ); + list_remove( &monitor->entry ); + free( monitor ); + } + + while (!list_empty( &sources )) + { + source = LIST_ENTRY( list_head( &sources ), struct source, entry ); + list_remove( &source->entry ); + source_release( source ); + } + + while (!list_empty( &gpus )) + { + gpu = LIST_ENTRY( list_head( &gpus ), struct gpu, entry ); + list_remove( &gpu->entry ); + gpu_release( gpu ); + } +} + static void prepare_devices(void) { char buffer[4096]; @@ -755,6 +790,8 @@ static void prepare_devices(void) DWORD size; HKEY hkey, subkey, device_key, prop_key;
+ clear_display_devices(); + if (!enum_key) enum_key = reg_create_ascii_key( NULL, enum_keyA, 0, NULL ); if (!control_key) control_key = reg_create_ascii_key( NULL, control_keyA, 0, NULL ); if (!video_key) video_key = reg_create_ascii_key( NULL, devicemap_video_keyA, REG_OPTION_VOLATILE, NULL ); @@ -1647,41 +1684,6 @@ static void release_display_manager_ctx( struct device_manager_ctx *ctx ) } }
-static void clear_display_devices(void) -{ - struct source *source; - struct monitor *monitor; - struct gpu *gpu; - - if (list_head( &monitors ) == &virtual_monitor.entry) - { - list_init( &monitors ); - return; - } - - while (!list_empty( &monitors )) - { - monitor = LIST_ENTRY( list_head( &monitors ), struct monitor, entry ); - if (monitor->source) source_release( monitor->source ); - list_remove( &monitor->entry ); - free( monitor ); - } - - while (!list_empty( &sources )) - { - source = LIST_ENTRY( list_head( &sources ), struct source, entry ); - list_remove( &source->entry ); - source_release( source ); - } - - while (!list_empty( &gpus )) - { - gpu = LIST_ENTRY( list_head( &gpus ), struct gpu, entry ); - list_remove( &gpu->entry ); - gpu_release( gpu ); - } -} - static BOOL is_detached_mode( const DEVMODEW *mode ) { return mode->dmFields & DM_POSITION &&
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 88 +++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 33 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index f42527a10a0..6292f77b955 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -340,14 +340,16 @@ static void release_display_device_init_mutex( HANDLE mutex )
static struct gpu *gpu_acquire( struct gpu *gpu ) { - InterlockedIncrement( &gpu->refcount ); + UINT ref = InterlockedIncrement( &gpu->refcount ); + TRACE( "gpu %p increasing refcount to %u\n", gpu, ref ); return gpu; }
static void gpu_release( struct gpu *gpu ) { - if (!InterlockedDecrement( &gpu->refcount )) - free( gpu ); + UINT ref = InterlockedDecrement( &gpu->refcount ); + TRACE( "gpu %p decreasing refcount to %u\n", gpu, ref ); + if (!ref) free( gpu ); }
static struct source *source_acquire( struct source *source ) @@ -957,7 +959,6 @@ struct device_manager_ctx UINT source_count; UINT monitor_count; HANDLE mutex; - struct gpu gpu; struct source source; HKEY source_key; struct list vulkan_gpus; @@ -1242,6 +1243,7 @@ static void add_gpu( const char *name, const struct pci_id *pci_id, const GUID * KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer; struct vulkan_gpu *vulkan_gpu = NULL; struct list *ptr; + struct gpu *gpu; unsigned int i; HKEY hkey, subkey; DWORD len; @@ -1261,8 +1263,9 @@ static void add_gpu( const char *name, const struct pci_id *pci_id, const GUID * prepare_devices(); }
- memset( &ctx->gpu, 0, sizeof(ctx->gpu) ); - ctx->gpu.index = ctx->gpu_count; + if (!(gpu = calloc( 1, sizeof(*gpu) ))) return; + gpu->refcount = 1; + gpu->index = ctx->gpu_count;
if ((vulkan_gpu = find_vulkan_gpu_from_uuid( ctx, vulkan_uuid ))) TRACE( "Found vulkan GPU matching uuid %s, pci_id %#04x:%#04x, name %s\n", debugstr_guid(&vulkan_gpu->uuid), @@ -1279,34 +1282,34 @@ static void add_gpu( const char *name, const struct pci_id *pci_id, const GUID * debugstr_guid(&vulkan_gpu->uuid), debugstr_a(vulkan_gpu->name)); }
- if (vulkan_uuid && !IsEqualGUID( vulkan_uuid, &empty_uuid )) ctx->gpu.vulkan_uuid = *vulkan_uuid; - else if (vulkan_gpu) ctx->gpu.vulkan_uuid = vulkan_gpu->uuid; + if (vulkan_uuid && !IsEqualGUID( vulkan_uuid, &empty_uuid )) gpu->vulkan_uuid = *vulkan_uuid; + else if (vulkan_gpu) gpu->vulkan_uuid = vulkan_gpu->uuid;
if (!pci_id->vendor && !pci_id->device && vulkan_gpu) pci_id = &vulkan_gpu->pci_id;
if ((!name || !strcmp( name, "Wine GPU" )) && vulkan_gpu) name = vulkan_gpu->name; - if (name) RtlUTF8ToUnicodeN( ctx->gpu.name, sizeof(ctx->gpu.name) - sizeof(WCHAR), &len, name, strlen( name ) ); + if (name) RtlUTF8ToUnicodeN( gpu->name, sizeof(gpu->name) - sizeof(WCHAR), &len, name, strlen( name ) );
- snprintf( ctx->gpu.path, sizeof(ctx->gpu.path), "PCI\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X\%08X", - pci_id->vendor, pci_id->device, pci_id->subsystem, pci_id->revision, ctx->gpu.index ); - if (!(hkey = reg_create_ascii_key( enum_key, ctx->gpu.path, 0, NULL ))) return; + snprintf( gpu->path, sizeof(gpu->path), "PCI\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X\%08X", + pci_id->vendor, pci_id->device, pci_id->subsystem, pci_id->revision, gpu->index ); + if (!(hkey = reg_create_ascii_key( enum_key, gpu->path, 0, NULL ))) return;
if ((subkey = reg_create_ascii_key( hkey, "Device Parameters", 0, NULL ))) { - if (query_reg_ascii_value( subkey, "VideoID", value, sizeof(buffer) ) != sizeof(ctx->gpu.guid) * sizeof(WCHAR)) + if (query_reg_ascii_value( subkey, "VideoID", value, sizeof(buffer) ) != sizeof(gpu->guid) * sizeof(WCHAR)) { GUID guid; uuid_create( &guid ); - snprintf( ctx->gpu.guid, sizeof(ctx->gpu.guid), "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + snprintf( gpu->guid, sizeof(gpu->guid), "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", (unsigned int)guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] ); - TRACE( "created guid %s\n", debugstr_a(ctx->gpu.guid) ); + TRACE( "created guid %s\n", debugstr_a(gpu->guid) ); } else { WCHAR *guidW = (WCHAR *)value->Data; - for (i = 0; i < sizeof(ctx->gpu.guid); i++) ctx->gpu.guid[i] = guidW[i]; - TRACE( "got guid %s\n", debugstr_a(ctx->gpu.guid) ); + for (i = 0; i < sizeof(gpu->guid); i++) gpu->guid[i] = guidW[i]; + TRACE( "got guid %s\n", debugstr_a(gpu->guid) ); } NtClose( subkey ); } @@ -1315,23 +1318,30 @@ static void add_gpu( const char *name, const struct pci_id *pci_id, const GUID * { if (query_reg_value( subkey, NULL, value, sizeof(buffer) ) != sizeof(LUID)) { - NtAllocateLocallyUniqueId( &ctx->gpu.luid ); - TRACE("allocated luid %08x%08x\n", (int)ctx->gpu.luid.HighPart, (int)ctx->gpu.luid.LowPart ); + NtAllocateLocallyUniqueId( &gpu->luid ); + TRACE("allocated luid %08x%08x\n", (int)gpu->luid.HighPart, (int)gpu->luid.LowPart ); } else { - memcpy( &ctx->gpu.luid, value->Data, sizeof(ctx->gpu.luid) ); - TRACE("got luid %08x%08x\n", (int)ctx->gpu.luid.HighPart, (int)ctx->gpu.luid.LowPart ); + memcpy( &gpu->luid, value->Data, sizeof(gpu->luid) ); + TRACE("got luid %08x%08x\n", (int)gpu->luid.HighPart, (int)gpu->luid.LowPart ); } NtClose( subkey ); }
NtClose( hkey );
- if (!write_gpu_to_registry( &ctx->gpu, pci_id, vulkan_gpu ? vulkan_gpu->memory : 0 )) - WARN( "Failed to write gpu to registry\n" ); + if (!write_gpu_to_registry( gpu, pci_id, vulkan_gpu ? vulkan_gpu->memory : 0 )) + { + WARN( "Failed to write gpu %p to registry\n", gpu ); + gpu_release( gpu ); + } else + { + list_add_tail( &gpus, &gpu->entry ); + TRACE( "created gpu %p\n", gpu ); ctx->gpu_count++; + }
if (vulkan_gpu) { @@ -1386,15 +1396,20 @@ static BOOL write_source_to_registry( const struct source *source, HKEY *source_ static void add_source( const char *name, UINT state_flags, UINT dpi, void *param ) { struct device_manager_ctx *ctx = param; + struct gpu *gpu;
TRACE( "name %s, state_flags %#x\n", name, state_flags );
+ assert( !list_empty( &gpus ) ); + gpu = LIST_ENTRY( list_tail( &gpus ), struct gpu, entry ); + /* in virtual desktop mode, report all physical sources as detached */ ctx->is_primary = !!(state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE); if (is_virtual_desktop()) state_flags &= ~(DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE);
+ if (ctx->source.gpu) gpu_release( ctx->source.gpu ); memset( &ctx->source, 0, sizeof(ctx->source) ); - ctx->source.gpu = &ctx->gpu; + ctx->source.gpu = gpu_acquire( gpu ); ctx->source.id = ctx->source_count + (ctx->has_primary ? 0 : 1); ctx->source.state_flags = state_flags; if (state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE) @@ -1406,13 +1421,13 @@ static void add_source( const char *name, UINT state_flags, UINT dpi, void *para
/* Wine specific config key where source settings will be held, symlinked with the logically indexed config key */ snprintf( ctx->source.path, sizeof(ctx->source.path), "%s\%s\Video\%s\Sources\%s", config_keyA, - control_keyA + strlen( "\Registry\Machine" ), ctx->gpu.guid, name ); + control_keyA + strlen( "\Registry\Machine" ), gpu->guid, name );
if (!write_source_to_registry( &ctx->source, &ctx->source_key )) WARN( "Failed to write source to registry\n" ); else { - ctx->gpu.source_count++; + gpu->source_count++; ctx->source_count++; } } @@ -1674,6 +1689,11 @@ static void release_display_manager_ctx( struct device_manager_ctx *ctx ) NtClose( ctx->source_key ); last_query_display_time = 0; } + if (ctx->source.gpu) + { + gpu_release( ctx->source.gpu ); + ctx->source.gpu = NULL; + } if (ctx->gpu_count) cleanup_devices();
while (!list_empty( &ctx->vulkan_gpus )) @@ -1967,13 +1987,13 @@ static BOOL get_default_desktop_size( DWORD *width, DWORD *height ) static BOOL add_virtual_source( struct device_manager_ctx *ctx ) { DEVMODEW current = {.dmSize = sizeof(current)}, initial = ctx->primary, maximum = ctx->primary, *modes; - struct source virtual_source = - { - .state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_VGA_COMPATIBLE, - .gpu = &ctx->gpu, - }; + struct source virtual_source = {.state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_VGA_COMPATIBLE}; struct gdi_monitor monitor = {0}; UINT modes_count; + struct gpu *gpu; + + assert( !list_empty( &gpus ) ); + gpu = LIST_ENTRY( list_tail( &gpus ), struct gpu, entry );
if (ctx->has_primary) ctx->source.id = ctx->source_count; else @@ -1981,19 +2001,21 @@ static BOOL add_virtual_source( struct device_manager_ctx *ctx ) virtual_source.state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE; ctx->has_primary = TRUE; } + virtual_source.gpu = gpu_acquire( gpu );
/* Wine specific config key where source settings will be held, symlinked with the logically indexed config key */ snprintf( virtual_source.path, sizeof(virtual_source.path), "%s\%s\Video\%s\Sources\%s", config_keyA, - control_keyA + strlen( "\Registry\Machine" ), virtual_source.gpu->guid, "Virtual" ); + control_keyA + strlen( "\Registry\Machine" ), gpu->guid, "Virtual" );
if (!write_source_to_registry( &virtual_source, &ctx->source_key )) { WARN( "Failed to write source to registry\n" ); + gpu_release( virtual_source.gpu ); return STATUS_UNSUCCESSFUL; }
ctx->source = virtual_source; - ctx->gpu.source_count++; + gpu->source_count++; ctx->source_count++;
if (!get_default_desktop_size( &initial.dmPelsWidth, &initial.dmPelsHeight ))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 45 +++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 22 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 6292f77b955..8f6b5cae4fb 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -112,6 +112,7 @@ struct source char path[MAX_PATH]; unsigned int id; struct gpu *gpu; + HKEY key; UINT dpi; UINT depth; /* emulated depth */ UINT state_flags; @@ -362,6 +363,7 @@ static void source_release( struct source *source ) { if (!InterlockedDecrement( &source->refcount )) { + if (source->key) NtClose( source->key ); gpu_release( source->gpu ); free( source->modes ); free( source ); @@ -960,7 +962,6 @@ struct device_manager_ctx UINT monitor_count; HANDLE mutex; struct source source; - HKEY source_key; struct list vulkan_gpus; BOOL has_primary; /* for the virtual desktop settings */ @@ -1350,7 +1351,7 @@ static void add_gpu( const char *name, const struct pci_id *pci_id, const GUID * } }
-static BOOL write_source_to_registry( const struct source *source, HKEY *source_key ) +static BOOL write_source_to_registry( struct source *source ) { struct gpu *gpu = source->gpu; unsigned int len, source_index = gpu->source_count; @@ -1375,12 +1376,11 @@ static BOOL write_source_to_registry( const struct source *source, HKEY *source_ NtClose( hkey );
/* Following information is Wine specific, it doesn't really exist on Windows. */ - if (*source_key) NtClose( *source_key ); - *source_key = reg_create_ascii_key( NULL, source->path, REG_OPTION_VOLATILE, NULL ); - set_reg_ascii_value( *source_key, "GPUID", gpu->path ); - set_reg_value( *source_key, state_flagsW, REG_DWORD, &source->state_flags, + source->key = reg_create_ascii_key( NULL, source->path, REG_OPTION_VOLATILE, NULL ); + set_reg_ascii_value( source->key, "GPUID", gpu->path ); + set_reg_value( source->key, state_flagsW, REG_DWORD, &source->state_flags, sizeof(source->state_flags) ); - set_reg_value( *source_key, dpiW, REG_DWORD, &source->dpi, sizeof(source->dpi) ); + set_reg_value( source->key, dpiW, REG_DWORD, &source->dpi, sizeof(source->dpi) );
snprintf( buffer, sizeof(buffer), "System\CurrentControlSet\Control\Video\%s\%04x", gpu->guid, source_index ); hkey = reg_create_ascii_key( config_key, buffer, REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, NULL ); @@ -1408,6 +1408,7 @@ static void add_source( const char *name, UINT state_flags, UINT dpi, void *para if (is_virtual_desktop()) state_flags &= ~(DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE);
if (ctx->source.gpu) gpu_release( ctx->source.gpu ); + if (ctx->source.key) NtClose( ctx->source.key ); memset( &ctx->source, 0, sizeof(ctx->source) ); ctx->source.gpu = gpu_acquire( gpu ); ctx->source.id = ctx->source_count + (ctx->has_primary ? 0 : 1); @@ -1423,7 +1424,7 @@ static void add_source( const char *name, UINT state_flags, UINT dpi, void *para snprintf( ctx->source.path, sizeof(ctx->source.path), "%s\%s\Video\%s\Sources\%s", config_keyA, control_keyA + strlen( "\Registry\Machine" ), gpu->guid, name );
- if (!write_source_to_registry( &ctx->source, &ctx->source_key )) + if (!write_source_to_registry( &ctx->source )) WARN( "Failed to write source to registry\n" ); else { @@ -1525,7 +1526,7 @@ static void add_monitor( const struct gdi_monitor *gdi_monitor, void *param )
snprintf( buffer, sizeof(buffer), "MonitorID%u", monitor.id ); snprintf( monitor.path, sizeof(monitor.path), "DISPLAY\%s\%04X&%04X", monitor_id_string, ctx->source.id, monitor.id ); - set_reg_ascii_value( ctx->source_key, buffer, monitor.path ); + set_reg_ascii_value( ctx->source.key, buffer, monitor.path );
if (!write_monitor_to_registry( &monitor, gdi_monitor->edid, gdi_monitor->edid_len )) WARN( "Failed to write monitor to registry\n" ); @@ -1637,12 +1638,12 @@ static void add_modes( const DEVMODEW *current, UINT modes_count, const DEVMODEW
if (modes_count > 1 || current == &detached) { - reg_delete_value( ctx->source_key, physicalW ); + reg_delete_value( ctx->source.key, physicalW ); virtual_modes = NULL; } else { - if (!read_source_mode( ctx->source_key, ENUM_CURRENT_SETTINGS, &virtual )) + if (!read_source_mode( ctx->source.key, ENUM_CURRENT_SETTINGS, &virtual )) virtual = physical;
if ((virtual_modes = get_virtual_modes( &virtual, current, &physical, &virtual_count ))) @@ -1651,17 +1652,17 @@ static void add_modes( const DEVMODEW *current, UINT modes_count, const DEVMODEW modes = virtual_modes; current = &virtual;
- write_source_mode( ctx->source_key, WINE_ENUM_PHYSICAL_SETTINGS, &physical ); + write_source_mode( ctx->source.key, WINE_ENUM_PHYSICAL_SETTINGS, &physical ); } }
- if (current == &detached || !read_source_mode( ctx->source_key, ENUM_REGISTRY_SETTINGS, &dummy )) - write_source_mode( ctx->source_key, ENUM_REGISTRY_SETTINGS, current ); - write_source_mode( ctx->source_key, ENUM_CURRENT_SETTINGS, current ); + if (current == &detached || !read_source_mode( ctx->source.key, ENUM_REGISTRY_SETTINGS, &dummy )) + write_source_mode( ctx->source.key, ENUM_REGISTRY_SETTINGS, current ); + write_source_mode( ctx->source.key, ENUM_CURRENT_SETTINGS, current );
assert( !modes_count || modes->dmDriverExtra == 0 ); - set_reg_value( ctx->source_key, modesW, REG_BINARY, modes, modes_count * sizeof(*modes) ); - set_reg_value( ctx->source_key, mode_countW, REG_DWORD, &modes_count, sizeof(modes_count) ); + set_reg_value( ctx->source.key, modesW, REG_BINARY, modes, modes_count * sizeof(*modes) ); + set_reg_value( ctx->source.key, mode_countW, REG_DWORD, &modes_count, sizeof(modes_count) ); ctx->source.mode_count = modes_count;
free( virtual_modes ); @@ -1684,9 +1685,9 @@ static void release_display_manager_ctx( struct device_manager_ctx *ctx ) ctx->mutex = 0; }
- if (ctx->source_key) + if (ctx->source.key) { - NtClose( ctx->source_key ); + NtClose( ctx->source.key ); last_query_display_time = 0; } if (ctx->source.gpu) @@ -1936,7 +1937,7 @@ static NTSTATUS default_update_display_devices( struct device_manager_ctx *ctx ) add_gpu( "Wine GPU", &pci_id, NULL, ctx ); add_source( "Default", source_flags, system_dpi, ctx );
- if (!read_source_mode( ctx->source_key, ENUM_CURRENT_SETTINGS, &mode )) + if (!read_source_mode( ctx->source.key, ENUM_CURRENT_SETTINGS, &mode )) { mode = modes[2]; mode.dmFields |= DM_POSITION; @@ -2007,7 +2008,7 @@ static BOOL add_virtual_source( struct device_manager_ctx *ctx ) snprintf( virtual_source.path, sizeof(virtual_source.path), "%s\%s\Video\%s\Sources\%s", config_keyA, control_keyA + strlen( "\Registry\Machine" ), gpu->guid, "Virtual" );
- if (!write_source_to_registry( &virtual_source, &ctx->source_key )) + if (!write_source_to_registry( &virtual_source )) { WARN( "Failed to write source to registry\n" ); gpu_release( virtual_source.gpu ); @@ -2024,7 +2025,7 @@ static BOOL add_virtual_source( struct device_manager_ctx *ctx ) initial.dmPelsHeight = maximum.dmPelsHeight; }
- if (!read_source_mode( ctx->source_key, ENUM_CURRENT_SETTINGS, ¤t )) + if (!read_source_mode( ctx->source.key, ENUM_CURRENT_SETTINGS, ¤t )) { current = ctx->primary; current.dmDisplayFrequency = 60;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 121 +++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 50 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 8f6b5cae4fb..878236f420f 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -355,13 +355,16 @@ static void gpu_release( struct gpu *gpu )
static struct source *source_acquire( struct source *source ) { - InterlockedIncrement( &source->refcount ); + UINT ref = InterlockedIncrement( &source->refcount ); + TRACE( "source %p increasing refcount to %u\n", source, ref ); return source; }
static void source_release( struct source *source ) { - if (!InterlockedDecrement( &source->refcount )) + UINT ref = InterlockedDecrement( &source->refcount ); + TRACE( "source %p decreasing refcount to %u\n", source, ref ); + if (!ref) { if (source->key) NtClose( source->key ); gpu_release( source->gpu ); @@ -961,7 +964,6 @@ struct device_manager_ctx UINT source_count; UINT monitor_count; HANDLE mutex; - struct source source; struct list vulkan_gpus; BOOL has_primary; /* for the virtual desktop settings */ @@ -1396,7 +1398,9 @@ static BOOL write_source_to_registry( struct source *source ) static void add_source( const char *name, UINT state_flags, UINT dpi, void *param ) { struct device_manager_ctx *ctx = param; + struct source *source; struct gpu *gpu; + BOOL is_primary;
TRACE( "name %s, state_flags %#x\n", name, state_flags );
@@ -1404,30 +1408,35 @@ static void add_source( const char *name, UINT state_flags, UINT dpi, void *para gpu = LIST_ENTRY( list_tail( &gpus ), struct gpu, entry );
/* in virtual desktop mode, report all physical sources as detached */ - ctx->is_primary = !!(state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE); + is_primary = !!(state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE); if (is_virtual_desktop()) state_flags &= ~(DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE);
- if (ctx->source.gpu) gpu_release( ctx->source.gpu ); - if (ctx->source.key) NtClose( ctx->source.key ); - memset( &ctx->source, 0, sizeof(ctx->source) ); - ctx->source.gpu = gpu_acquire( gpu ); - ctx->source.id = ctx->source_count + (ctx->has_primary ? 0 : 1); - ctx->source.state_flags = state_flags; + if (!(source = calloc( 1, sizeof(*source) ))) return; + source->refcount = 1; + source->gpu = gpu_acquire( gpu ); + source->id = ctx->source_count + (ctx->has_primary ? 0 : 1); + source->state_flags = state_flags; if (state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE) { - ctx->source.id = 0; + source->id = 0; ctx->has_primary = TRUE; } - ctx->source.dpi = dpi; + source->dpi = dpi;
/* Wine specific config key where source settings will be held, symlinked with the logically indexed config key */ - snprintf( ctx->source.path, sizeof(ctx->source.path), "%s\%s\Video\%s\Sources\%s", config_keyA, + snprintf( source->path, sizeof(source->path), "%s\%s\Video\%s\Sources\%s", config_keyA, control_keyA + strlen( "\Registry\Machine" ), gpu->guid, name );
- if (!write_source_to_registry( &ctx->source )) - WARN( "Failed to write source to registry\n" ); + if (!write_source_to_registry( source )) + { + WARN( "Failed to write source %p to registry\n", source ); + source_release( source ); + } else { + list_add_tail( &sources, &source->entry ); + TRACE( "created source %p for gpu %p\n", source, gpu ); + ctx->is_primary = is_primary; gpu->source_count++; ctx->source_count++; } @@ -1508,11 +1517,15 @@ static void add_monitor( const struct gdi_monitor *gdi_monitor, void *param ) { struct device_manager_ctx *ctx = param; struct monitor monitor = {0}; + struct source *source; char buffer[MAX_PATH]; char monitor_id_string[16];
- monitor.source = &ctx->source; - monitor.id = ctx->source.monitor_count; + assert( !list_empty( &sources ) ); + source = LIST_ENTRY( list_tail( &sources ), struct source, entry ); + + monitor.source = source_acquire( source ); + monitor.id = source->monitor_count; monitor.output_id = ctx->monitor_count; monitor.rc_work = gdi_monitor->rc_work;
@@ -1525,16 +1538,18 @@ static void add_monitor( const struct gdi_monitor *gdi_monitor, void *param ) strcpy( monitor_id_string, "Default_Monitor" );
snprintf( buffer, sizeof(buffer), "MonitorID%u", monitor.id ); - snprintf( monitor.path, sizeof(monitor.path), "DISPLAY\%s\%04X&%04X", monitor_id_string, ctx->source.id, monitor.id ); - set_reg_ascii_value( ctx->source.key, buffer, monitor.path ); + snprintf( monitor.path, sizeof(monitor.path), "DISPLAY\%s\%04X&%04X", monitor_id_string, source->id, monitor.id ); + set_reg_ascii_value( source->key, buffer, monitor.path );
if (!write_monitor_to_registry( &monitor, gdi_monitor->edid, gdi_monitor->edid_len )) WARN( "Failed to write monitor to registry\n" ); else { - ctx->source.monitor_count++; + source->monitor_count++; ctx->monitor_count++; } + + source_release( monitor.source ); }
static DEVMODEW *get_virtual_modes( const DEVMODEW *current, const DEVMODEW *initial, @@ -1626,24 +1641,28 @@ static void add_modes( const DEVMODEW *current, UINT modes_count, const DEVMODEW struct device_manager_ctx *ctx = param; DEVMODEW dummy, detached = *current, virtual, *virtual_modes = NULL; const DEVMODEW physical = modes_count == 1 ? *modes : *current; + struct source *source; UINT virtual_count;
TRACE( "current %s, modes_count %u, modes %p, param %p\n", debugstr_devmodew( current ), modes_count, modes, param );
+ assert( !list_empty( &sources ) ); + source = LIST_ENTRY( list_tail( &sources ), struct source, entry ); + if (ctx->is_primary) ctx->primary = *current;
detached.dmPelsWidth = 0; detached.dmPelsHeight = 0; - if (!(ctx->source.state_flags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) current = &detached; + if (!(source->state_flags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) current = &detached;
if (modes_count > 1 || current == &detached) { - reg_delete_value( ctx->source.key, physicalW ); + reg_delete_value( source->key, physicalW ); virtual_modes = NULL; } else { - if (!read_source_mode( ctx->source.key, ENUM_CURRENT_SETTINGS, &virtual )) + if (!read_source_mode( source->key, ENUM_CURRENT_SETTINGS, &virtual )) virtual = physical;
if ((virtual_modes = get_virtual_modes( &virtual, current, &physical, &virtual_count ))) @@ -1652,18 +1671,18 @@ static void add_modes( const DEVMODEW *current, UINT modes_count, const DEVMODEW modes = virtual_modes; current = &virtual;
- write_source_mode( ctx->source.key, WINE_ENUM_PHYSICAL_SETTINGS, &physical ); + write_source_mode( source->key, WINE_ENUM_PHYSICAL_SETTINGS, &physical ); } }
- if (current == &detached || !read_source_mode( ctx->source.key, ENUM_REGISTRY_SETTINGS, &dummy )) - write_source_mode( ctx->source.key, ENUM_REGISTRY_SETTINGS, current ); - write_source_mode( ctx->source.key, ENUM_CURRENT_SETTINGS, current ); + if (current == &detached || !read_source_mode( source->key, ENUM_REGISTRY_SETTINGS, &dummy )) + write_source_mode( source->key, ENUM_REGISTRY_SETTINGS, current ); + write_source_mode( source->key, ENUM_CURRENT_SETTINGS, current );
assert( !modes_count || modes->dmDriverExtra == 0 ); - set_reg_value( ctx->source.key, modesW, REG_BINARY, modes, modes_count * sizeof(*modes) ); - set_reg_value( ctx->source.key, mode_countW, REG_DWORD, &modes_count, sizeof(modes_count) ); - ctx->source.mode_count = modes_count; + set_reg_value( source->key, modesW, REG_BINARY, modes, modes_count * sizeof(*modes) ); + set_reg_value( source->key, mode_countW, REG_DWORD, &modes_count, sizeof(modes_count) ); + source->mode_count = modes_count;
free( virtual_modes ); } @@ -1685,16 +1704,7 @@ static void release_display_manager_ctx( struct device_manager_ctx *ctx ) ctx->mutex = 0; }
- if (ctx->source.key) - { - NtClose( ctx->source.key ); - last_query_display_time = 0; - } - if (ctx->source.gpu) - { - gpu_release( ctx->source.gpu ); - ctx->source.gpu = NULL; - } + if (!list_empty( &sources )) last_query_display_time = 0; if (ctx->gpu_count) cleanup_devices();
while (!list_empty( &ctx->vulkan_gpus )) @@ -1933,11 +1943,15 @@ static NTSTATUS default_update_display_devices( struct device_manager_ctx *ctx ) struct pci_id pci_id = {0}; struct gdi_monitor monitor = {0}; DEVMODEW mode = {.dmSize = sizeof(mode)}; + struct source *source;
add_gpu( "Wine GPU", &pci_id, NULL, ctx ); add_source( "Default", source_flags, system_dpi, ctx );
- if (!read_source_mode( ctx->source.key, ENUM_CURRENT_SETTINGS, &mode )) + assert( !list_empty( &sources ) ); + source = LIST_ENTRY( list_tail( &sources ), struct source, entry ); + + if (!read_source_mode( source->key, ENUM_CURRENT_SETTINGS, &mode )) { mode = modes[2]; mode.dmFields |= DM_POSITION; @@ -1988,7 +2002,7 @@ static BOOL get_default_desktop_size( DWORD *width, DWORD *height ) static BOOL add_virtual_source( struct device_manager_ctx *ctx ) { DEVMODEW current = {.dmSize = sizeof(current)}, initial = ctx->primary, maximum = ctx->primary, *modes; - struct source virtual_source = {.state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_VGA_COMPATIBLE}; + struct source *physical, *source; struct gdi_monitor monitor = {0}; UINT modes_count; struct gpu *gpu; @@ -1996,26 +2010,33 @@ static BOOL add_virtual_source( struct device_manager_ctx *ctx ) assert( !list_empty( &gpus ) ); gpu = LIST_ENTRY( list_tail( &gpus ), struct gpu, entry );
- if (ctx->has_primary) ctx->source.id = ctx->source_count; + if (list_empty( &sources )) physical = NULL; + else physical = LIST_ENTRY( list_tail( &sources ), struct source, entry ); + + if (!(source = calloc( 1, sizeof(*source) ))) return STATUS_NO_MEMORY; + source->refcount = 1; + source->state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_VGA_COMPATIBLE; + + if (ctx->has_primary && physical) physical->id = ctx->source_count; else { - virtual_source.state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE; + source->state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE; ctx->has_primary = TRUE; } - virtual_source.gpu = gpu_acquire( gpu ); + source->gpu = gpu_acquire( gpu );
/* Wine specific config key where source settings will be held, symlinked with the logically indexed config key */ - snprintf( virtual_source.path, sizeof(virtual_source.path), "%s\%s\Video\%s\Sources\%s", config_keyA, + snprintf( source->path, sizeof(source->path), "%s\%s\Video\%s\Sources\%s", config_keyA, control_keyA + strlen( "\Registry\Machine" ), gpu->guid, "Virtual" );
- if (!write_source_to_registry( &virtual_source )) + if (!write_source_to_registry( source )) { WARN( "Failed to write source to registry\n" ); - gpu_release( virtual_source.gpu ); + source_release( source ); return STATUS_UNSUCCESSFUL; }
- ctx->source = virtual_source; + list_add_tail( &sources, &source->entry ); gpu->source_count++; ctx->source_count++;
@@ -2025,7 +2046,7 @@ static BOOL add_virtual_source( struct device_manager_ctx *ctx ) initial.dmPelsHeight = maximum.dmPelsHeight; }
- if (!read_source_mode( ctx->source.key, ENUM_CURRENT_SETTINGS, ¤t )) + if (!read_source_mode( source->key, ENUM_CURRENT_SETTINGS, ¤t )) { current = ctx->primary; current.dmDisplayFrequency = 60;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 53 +++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 18 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 878236f420f..50020ed80d0 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -140,6 +140,7 @@ struct edid_monitor_info
struct monitor { + LONG refcount; struct list entry; char path[MAX_PATH]; struct source *source; @@ -373,6 +374,17 @@ static void source_release( struct source *source ) } }
+static void monitor_release( struct monitor *monitor ) +{ + UINT ref = InterlockedDecrement( &monitor->refcount ); + TRACE( "monitor %p decreasing refcount to %u\n", monitor, ref ); + if (!ref) + { + if (monitor->source) source_release( monitor->source ); + free( monitor ); + } +} + C_ASSERT(sizeof(DEVMODEW) - offsetof(DEVMODEW, dmFields) == 0x94);
static void get_monitor_info_from_edid( struct edid_monitor_info *info, const unsigned char *edid, unsigned int edid_len ) @@ -767,9 +779,8 @@ static void clear_display_devices(void) while (!list_empty( &monitors )) { monitor = LIST_ENTRY( list_head( &monitors ), struct monitor, entry ); - if (monitor->source) source_release( monitor->source ); list_remove( &monitor->entry ); - free( monitor ); + monitor_release( monitor ); }
while (!list_empty( &sources )) @@ -1516,7 +1527,7 @@ static BOOL write_monitor_to_registry( struct monitor *monitor, const BYTE *edid static void add_monitor( const struct gdi_monitor *gdi_monitor, void *param ) { struct device_manager_ctx *ctx = param; - struct monitor monitor = {0}; + struct monitor *monitor; struct source *source; char buffer[MAX_PATH]; char monitor_id_string[16]; @@ -1524,32 +1535,37 @@ static void add_monitor( const struct gdi_monitor *gdi_monitor, void *param ) assert( !list_empty( &sources ) ); source = LIST_ENTRY( list_tail( &sources ), struct source, entry );
- monitor.source = source_acquire( source ); - monitor.id = source->monitor_count; - monitor.output_id = ctx->monitor_count; - monitor.rc_work = gdi_monitor->rc_work; + if (!(monitor = calloc( 1, sizeof(*monitor) ))) return; + monitor->refcount = 1; + monitor->source = source_acquire( source ); + monitor->id = source->monitor_count; + monitor->output_id = ctx->monitor_count; + monitor->rc_work = gdi_monitor->rc_work;
- TRACE( "%u %s %s\n", monitor.id, wine_dbgstr_rect(&gdi_monitor->rc_monitor), wine_dbgstr_rect(&gdi_monitor->rc_work) ); + TRACE( "%u %s %s\n", monitor->id, wine_dbgstr_rect(&gdi_monitor->rc_monitor), wine_dbgstr_rect(&gdi_monitor->rc_work) );
- get_monitor_info_from_edid( &monitor.edid_info, gdi_monitor->edid, gdi_monitor->edid_len ); - if (monitor.edid_info.flags & MONITOR_INFO_HAS_MONITOR_ID) - strcpy( monitor_id_string, monitor.edid_info.monitor_id_string ); + get_monitor_info_from_edid( &monitor->edid_info, gdi_monitor->edid, gdi_monitor->edid_len ); + if (monitor->edid_info.flags & MONITOR_INFO_HAS_MONITOR_ID) + strcpy( monitor_id_string, monitor->edid_info.monitor_id_string ); else strcpy( monitor_id_string, "Default_Monitor" );
- snprintf( buffer, sizeof(buffer), "MonitorID%u", monitor.id ); - snprintf( monitor.path, sizeof(monitor.path), "DISPLAY\%s\%04X&%04X", monitor_id_string, source->id, monitor.id ); - set_reg_ascii_value( source->key, buffer, monitor.path ); + snprintf( buffer, sizeof(buffer), "MonitorID%u", monitor->id ); + snprintf( monitor->path, sizeof(monitor->path), "DISPLAY\%s\%04X&%04X", monitor_id_string, source->id, monitor->id ); + set_reg_ascii_value( source->key, buffer, monitor->path );
- if (!write_monitor_to_registry( &monitor, gdi_monitor->edid, gdi_monitor->edid_len )) - WARN( "Failed to write monitor to registry\n" ); + if (!write_monitor_to_registry( monitor, gdi_monitor->edid, gdi_monitor->edid_len )) + { + WARN( "Failed to write monitor %p to registry\n", monitor ); + monitor_release( monitor ); + } else { + list_add_tail( &monitors, &monitor->entry ); + TRACE( "created monitor %p for source %p\n", monitor, source ); source->monitor_count++; ctx->monitor_count++; } - - source_release( monitor.source ); }
static DEVMODEW *get_virtual_modes( const DEVMODEW *current, const DEVMODEW *initial, @@ -1812,6 +1828,7 @@ static void enum_monitors( const char *path ) { struct monitor *monitor; if (!(monitor = calloc( 1, sizeof(*monitor) ))) return; + monitor->refcount = 1; strcpy( monitor->path, path ); list_add_tail( &monitors, &monitor->entry ); }