[PATCH 6/6] winex11.drv: Add a cache for querying XRandR 1.4 current modes.

Zhiyi Zhang zzhang at codeweavers.com
Tue May 18 04:14:29 CDT 2021


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51047
Signed-off-by: Zhiyi Zhang <zzhang at 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, &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;
 }
 
-- 
2.30.2



More information about the wine-devel mailing list