[PATCH 1/2] win32u: Cache GL driver functions in DC.

Paul Gofman pgofman at codeweavers.com
Fri Jan 21 05:36:03 CST 2022


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
     Runescape calls GL functions (SwapBuffers, glFinish) from different threads.
     That mostly goes well except for when the DC is locked by ExtEscape() and the
     other thread calls, e. g., SwapBuffers that fails because GL can't get driver
     funcs (get_dc_ptr() in__wine_get_wgl_driver() returns NULL as the DC is locked
     by the other thread).

     I don't see any reason why getting GL funcs should fail in this case. Caching
     gl_funcs and using them with get_dc_obj() locking solves this type of race.

 dlls/win32u/dc.c            | 19 -------------------
 dlls/win32u/driver.c        | 20 ++++++++++++--------
 dlls/win32u/ntgdi_private.h | 21 +++++++++++++++++++++
 3 files changed, 33 insertions(+), 27 deletions(-)

diff --git a/dlls/win32u/dc.c b/dlls/win32u/dc.c
index 3aae73779e9..9c09bf66e03 100644
--- a/dlls/win32u/dc.c
+++ b/dlls/win32u/dc.c
@@ -63,25 +63,6 @@ static const struct gdi_obj_funcs dc_funcs =
 };
 
 
-static inline DC *get_dc_obj( HDC hdc )
-{
-    DWORD type;
-    DC *dc = get_any_obj_ptr( hdc, &type );
-    if (!dc) return NULL;
-
-    switch (type)
-    {
-    case NTGDI_OBJ_DC:
-    case NTGDI_OBJ_MEMDC:
-    case NTGDI_OBJ_ENHMETADC:
-        return dc;
-    default:
-        GDI_ReleaseObj( hdc );
-        SetLastError( ERROR_INVALID_HANDLE );
-        return NULL;
-    }
-}
-
 /* alloc DC_ATTR from a pool of memory accessible from client */
 static DC_ATTR *alloc_dc_attr(void)
 {
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c
index 39996086c6d..233427b0964 100644
--- a/dlls/win32u/driver.c
+++ b/dlls/win32u/driver.c
@@ -1347,14 +1347,18 @@ NTSTATUS WINAPI NtGdiDdDDICheckVidPnExclusiveOwnership( const D3DKMT_CHECKVIDPNE
  */
 struct opengl_funcs * CDECL __wine_get_wgl_driver( HDC hdc, UINT version )
 {
-    struct opengl_funcs *ret = NULL;
-    DC * dc = get_dc_ptr( hdc );
+    struct opengl_funcs *ret;
+    PHYSDEV physdev;
+    DC * dc;
 
-    if (dc)
-    {
-        PHYSDEV physdev = GET_DC_PHYSDEV( dc, wine_get_wgl_driver );
-        ret = physdev->funcs->wine_get_wgl_driver( physdev, version );
-        release_dc_ptr( dc );
-    }
+    if (!(dc = get_dc_obj( hdc ))) return NULL;
+    ret = dc->gl_funcs;
+    GDI_ReleaseObj( hdc );
+    if (ret) return ret;
+
+    if (!(dc = get_dc_ptr( hdc ))) return NULL;
+    physdev = GET_DC_PHYSDEV( dc, wine_get_wgl_driver );
+    dc->gl_funcs = ret = physdev->funcs->wine_get_wgl_driver( physdev, version );
+    release_dc_ptr( dc );
     return ret;
 }
diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h
index bfeb4557da7..54a4dc17eaf 100644
--- a/dlls/win32u/ntgdi_private.h
+++ b/dlls/win32u/ntgdi_private.h
@@ -87,6 +87,8 @@ typedef struct tagDC
     XFORM         xformVport2World;  /* Inverse of the above transformation */
     BOOL          vport2WorldValid;  /* Is xformVport2World valid? */
     RECT          bounds;            /* Current bounding rect */
+
+    struct opengl_funcs *gl_funcs;   /* Opengl driver functions */
 } DC;
 
 /* Certain functions will do no further processing if the driver returns this.
@@ -660,6 +662,25 @@ static inline void copy_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *src )
     memcpy( dst, src, get_dib_info_size( src, DIB_RGB_COLORS ));
 }
 
+static inline DC *get_dc_obj( HDC hdc )
+{
+    DWORD type;
+    DC *dc = get_any_obj_ptr( hdc, &type );
+    if (!dc) return NULL;
+
+    switch (type)
+    {
+    case NTGDI_OBJ_DC:
+    case NTGDI_OBJ_MEMDC:
+    case NTGDI_OBJ_ENHMETADC:
+        return dc;
+    default:
+        GDI_ReleaseObj( hdc );
+        SetLastError( ERROR_INVALID_HANDLE );
+        return NULL;
+    }
+}
+
 extern void CDECL free_heap_bits( struct gdi_image_bits *bits ) DECLSPEC_HIDDEN;
 
 void set_gdi_client_ptr( HGDIOBJ handle, void *ptr ) DECLSPEC_HIDDEN;
-- 
2.34.1




More information about the wine-devel mailing list