winex11.drv: Add a cache for querying XRandR 1.4 current modes.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51047
Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zhiyi Zhang 2021-05-18 17:14:29 +08:00 committed by Alexandre Julliard
parent 095bdc6c43
commit 7fabcf6fed
1 changed files with 106 additions and 18 deletions

View File

@ -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, &current_modes_section,
{&current_modes_critsect_debug.ProcessLocksList, &current_modes_critsect_debug.ProcessLocksList},
0, 0, {(DWORD_PTR)(__FILE__ ": current_modes_section")}
};
static CRITICAL_SECTION current_modes_section = {&current_modes_critsect_debug, -1, 0, 0, 0, 0};
static void xrandr14_invalidate_current_mode_cache(void)
{
EnterCriticalSection( &current_modes_section );
heap_free( current_modes);
current_modes = NULL;
current_mode_count = 0;
LeaveCriticalSection( &current_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( &current_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( &current_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( &current_modes_section );
return FALSE;
}
*id = current_modes[display_idx].id;
LeaveCriticalSection( &current_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( &current_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, &current_modes[mode_idx].mode, sizeof(*mode) );
LeaveCriticalSection( &current_modes_section );
return TRUE;
}
LeaveCriticalSection( &current_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( &current_modes_section );
for (mode_idx = 0; mode_idx < current_mode_count; ++mode_idx)
{
if (current_modes[mode_idx].id != id)
continue;
memcpy( &current_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( &current_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;
}