Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51047 Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/winex11.drv/xrandr.c | 124 ++++++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index fa748c2af04..c3af35d8ec3 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -324,6 +324,32 @@ static LONG xrandr10_set_current_mode( ULONG_PTR id, DEVMODEW *mode )
#ifdef HAVE_XRRGETPROVIDERRESOURCES
+static struct current_mode +{ + ULONG_PTR id; + BOOL loaded; + DEVMODEW mode; +} *current_modes; +static int current_mode_count; + +static CRITICAL_SECTION current_modes_section; +static CRITICAL_SECTION_DEBUG current_modes_critsect_debug = +{ + 0, 0, ¤t_modes_section, + {¤t_modes_critsect_debug.ProcessLocksList, ¤t_modes_critsect_debug.ProcessLocksList}, + 0, 0, {(DWORD_PTR)(__FILE__ ": current_modes_section")} +}; +static CRITICAL_SECTION current_modes_section = {¤t_modes_critsect_debug, -1, 0, 0, 0, 0}; + +static void xrandr14_invalidate_current_mode_cache(void) +{ + EnterCriticalSection( ¤t_modes_section ); + heap_free( current_modes); + current_modes = NULL; + current_mode_count = 0; + LeaveCriticalSection( ¤t_modes_section ); +} + static XRRScreenResources *xrandr_get_screen_resources(void) { XRRScreenResources *resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window ); @@ -1115,6 +1141,7 @@ static void xrandr14_free_monitors( struct x11drv_monitor *monitors )
static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event ) { + xrandr14_invalidate_current_mode_cache(); if (hwnd == GetDesktopWindow() && GetWindowThreadProcessId( hwnd, NULL ) == GetCurrentThreadId()) { /* Don't send a WM_DISPLAYCHANGE message here because this event may be a result from @@ -1148,7 +1175,8 @@ static void xrandr14_register_event_handlers(void) /* XRandR 1.4 display settings handler */ static BOOL xrandr14_get_id( const WCHAR *device_name, ULONG_PTR *id ) { - INT gpu_count, adapter_count, display_count = 0; + struct current_mode *tmp_modes, *new_current_modes = NULL; + INT gpu_count, adapter_count, new_current_mode_count = 0; INT gpu_idx, adapter_idx, display_idx; struct x11drv_adapter *adapters; struct x11drv_gpu *gpus; @@ -1159,31 +1187,60 @@ static BOOL xrandr14_get_id( const WCHAR *device_name, ULONG_PTR *id ) if (*end) return FALSE;
- if (!xrandr14_get_gpus2( &gpus, &gpu_count, FALSE )) - return FALSE; - - for (gpu_idx = 0; gpu_idx < gpu_count; ++gpu_idx) + /* Update cache */ + EnterCriticalSection( ¤t_modes_section ); + if (!current_modes) { - if (!xrandr14_get_adapters( gpus[gpu_idx].id, &adapters, &adapter_count )) + if (!xrandr14_get_gpus2( &gpus, &gpu_count, FALSE )) { - xrandr14_free_gpus( gpus ); + LeaveCriticalSection( ¤t_modes_section ); return FALSE; }
- adapter_idx = display_idx - display_count; - if (adapter_idx < adapter_count) + for (gpu_idx = 0; gpu_idx < gpu_count; ++gpu_idx) { - *id = adapters[adapter_idx].id; - xrandr14_free_adapters( adapters ); - xrandr14_free_gpus( gpus ); - return TRUE; - } + if (!xrandr14_get_adapters( gpus[gpu_idx].id, &adapters, &adapter_count )) + break;
- display_count += adapter_count; - xrandr14_free_adapters( adapters ); + if (!new_current_modes) + tmp_modes = heap_alloc( adapter_count * sizeof(*tmp_modes) ); + else + tmp_modes = heap_realloc( new_current_modes, (new_current_mode_count + adapter_count) * sizeof(*tmp_modes) ); + + if (!tmp_modes) + { + xrandr14_free_adapters( adapters ); + break; + } + new_current_modes = tmp_modes; + + for (adapter_idx = 0; adapter_idx < adapter_count; ++adapter_idx) + { + new_current_modes[new_current_mode_count + adapter_idx].id = adapters[adapter_idx].id; + new_current_modes[new_current_mode_count + adapter_idx].loaded = FALSE; + } + new_current_mode_count += adapter_count; + xrandr14_free_adapters( adapters ); + } + xrandr14_free_gpus( gpus ); + + if (new_current_modes) + { + heap_free( current_modes ); + current_modes = new_current_modes; + current_mode_count = new_current_mode_count; + } } - xrandr14_free_gpus( gpus ); - return FALSE; + + if (display_idx >= current_mode_count) + { + LeaveCriticalSection( ¤t_modes_section ); + return FALSE; + } + + *id = current_modes[display_idx].id; + LeaveCriticalSection( ¤t_modes_section ); + return TRUE; }
static void add_xrandr14_mode( DEVMODEW *mode, XRRModeInfo *info, DWORD depth, DWORD frequency, @@ -1342,6 +1399,21 @@ static BOOL xrandr14_get_current_mode( ULONG_PTR id, DEVMODEW *mode ) RECT primary; INT mode_idx;
+ EnterCriticalSection( ¤t_modes_section ); + for (mode_idx = 0; mode_idx < current_mode_count; ++mode_idx) + { + if (current_modes[mode_idx].id != id) + continue; + + if (!current_modes[mode_idx].loaded) + break; + + memcpy( mode, ¤t_modes[mode_idx].mode, sizeof(*mode) ); + LeaveCriticalSection( ¤t_modes_section ); + return TRUE; + } + LeaveCriticalSection( ¤t_modes_section ); + screen_resources = xrandr_get_screen_resources(); if (!screen_resources) goto done; @@ -1400,6 +1472,21 @@ static BOOL xrandr14_get_current_mode( ULONG_PTR id, DEVMODEW *mode ) mode->u1.s2.dmPosition.x = crtc_info->x - primary.left; mode->u1.s2.dmPosition.y = crtc_info->y - primary.top; ret = TRUE; + + EnterCriticalSection( ¤t_modes_section ); + for (mode_idx = 0; mode_idx < current_mode_count; ++mode_idx) + { + if (current_modes[mode_idx].id != id) + continue; + + memcpy( ¤t_modes[mode_idx].mode, mode, sizeof(*mode) ); + current_modes[mode_idx].mode.dmSize = sizeof(*mode); + current_modes[mode_idx].mode.dmDriverExtra = 0; + current_modes[mode_idx].loaded = TRUE; + break; + } + LeaveCriticalSection( ¤t_modes_section ); + done: if (crtc_info) pXRRFreeCrtcInfo( crtc_info ); @@ -1517,6 +1604,7 @@ done: if (output_info) pXRRFreeOutputInfo( output_info ); pXRRFreeScreenResources( screen_resources ); + xrandr14_invalidate_current_mode_cache(); return ret; }