[PATCH 2/2] winex11: track glx windows per thread

Miklós Máté mtmkls at gmail.com
Wed Jul 20 16:35:56 CDT 2016


XCloseDisplay in thread_detach() closes all X windows, but the GLX windows
remain, and become zombies. If a new X window is created with the same XID,
Mesa refuses to attach a GLX window to it because of the zombie. Observed
in the ddraw test.

Signed-off-by: Miklós Máté <mtmkls at gmail.com>
---
 dlls/winex11.drv/opengl.c      | 52 ++++++++++++++++++++++++++++++++++++++++++
 dlls/winex11.drv/x11drv.h      |  2 ++
 dlls/winex11.drv/x11drv_main.c |  2 ++
 3 files changed, 56 insertions(+)

diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c
index 86b91ec..d11a9b6 100644
--- a/dlls/winex11.drv/opengl.c
+++ b/dlls/winex11.drv/opengl.c
@@ -265,6 +265,12 @@ struct gl_drawable
     BOOL                           refresh_swap_interval;
 };
 
+struct gl_hwnd
+{
+    HWND        hwnd;
+    struct list entry;
+};
+
 enum glx_swap_control_method
 {
     GLX_SWAP_CONTROL_NONE,
@@ -1419,6 +1425,8 @@ static BOOL create_gl_drawable( HWND hwnd, struct gl_drawable *gl, struct x11drv
 static BOOL set_win_format( HWND hwnd, const struct wgl_pixel_format *format )
 {
     struct gl_drawable *gl, *prev;
+    struct gl_hwnd *glh;
+    struct x11drv_thread_data *thr_data;
     Window old_client_window;
     struct x11drv_win_data *data;
 
@@ -1457,6 +1465,13 @@ static BOOL set_win_format( HWND hwnd, const struct wgl_pixel_format *format )
     TRACE( "created GL drawable %lx for win %p %s\n",
            gl->drawable, hwnd, debugstr_fbconfig( format->fbconfig ));
 
+    thr_data = TlsGetValue( thread_data_tls_index );
+    if (thr_data)
+    {
+        glh = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*glh) );
+        glh->hwnd = hwnd;
+        list_add_head( &thr_data->gl_drawables, &glh->entry );
+    }
     XFlush( gdi_display );
 
     EnterCriticalSection( &context_section );
@@ -1636,17 +1651,54 @@ done:
 void destroy_gl_drawable( HWND hwnd )
 {
     struct gl_drawable *gl;
+    struct gl_hwnd *glh, *glh2;
+    struct x11drv_thread_data *thr_data;
 
     EnterCriticalSection( &context_section );
     if (!XFindContext( gdi_display, (XID)hwnd, gl_hwnd_context, (char **)&gl ))
     {
         XDeleteContext( gdi_display, (XID)hwnd, gl_hwnd_context );
         free_gl_drawable( gl );
+
+        thr_data = TlsGetValue( thread_data_tls_index );
+        if (thr_data)
+        {
+            LIST_FOR_EACH_ENTRY_SAFE( glh, glh2, &thr_data->gl_drawables, struct gl_hwnd, entry )
+            {
+                if (glh->hwnd == hwnd)
+                {
+                    list_remove( &glh->entry );
+                    HeapFree( GetProcessHeap(), 0, glh );
+                }
+            }
+        }
         XSync( gdi_display, False );
     }
     LeaveCriticalSection( &context_section );
 }
 
+/***********************************************************************
+ *              destroy_all_gl_drawables
+ */
+void destroy_all_gl_drawables( struct x11drv_thread_data *data )
+{
+    struct gl_drawable *gl;
+    struct gl_hwnd *glh, *glh2;
+
+    EnterCriticalSection( &context_section );
+    LIST_FOR_EACH_ENTRY_SAFE( glh, glh2, &data->gl_drawables, struct gl_hwnd, entry )
+    {
+        if (!XFindContext( gdi_display, (XID)(glh->hwnd), gl_hwnd_context, (char **)&gl ))
+        {
+            XDeleteContext( gdi_display, (XID)(glh->hwnd), gl_hwnd_context );
+            free_gl_drawable( gl );
+        }
+        list_remove( &glh->entry );
+        HeapFree( GetProcessHeap(), 0, glh->hwnd );
+    }
+    XSync( gdi_display, False );
+    LeaveCriticalSection( &context_section );
+}
 
 /**
  * glxdrv_DescribePixelFormat
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 2180851..2dfff6e 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -326,6 +326,7 @@ struct x11drv_thread_data
     void    *xi2_devices;          /* list of XInput2 devices (valid when state is enabled) */
     int      xi2_device_count;
     int      xi2_core_pointer;     /* XInput2 core pointer id */
+    struct list gl_drawables;      /* list of gl drawables created */
 };
 
 extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN;
@@ -576,6 +577,7 @@ extern XIC X11DRV_get_ic( HWND hwnd ) DECLSPEC_HIDDEN;
 extern void sync_gl_drawable( HWND hwnd, const RECT *visible_rect, const RECT *client_rect ) DECLSPEC_HIDDEN;
 extern void set_gl_drawable_parent( HWND hwnd, HWND parent ) DECLSPEC_HIDDEN;
 extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN;
+extern void destroy_all_gl_drawables( struct x11drv_thread_data *data ) DECLSPEC_HIDDEN;
 
 extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN;
 extern Window init_clip_window(void) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index d4f5c84..0b90afd 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -608,6 +608,7 @@ static void thread_detach(void)
         X11DRV_ResetSelectionOwner();
         if (data->xim) XCloseIM( data->xim );
         if (data->font_set) XFreeFontSet( data->display, data->font_set );
+        destroy_all_gl_drawables( data );
         XCloseDisplay( data->display );
         HeapFree( GetProcessHeap(), 0, data );
         /* clear data in case we get re-entered from user32 before the thread is truly dead */
@@ -672,6 +673,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
     if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
 
     set_queue_display_fd( data->display );
+    list_init( &data->gl_drawables );
     TlsSetValue( thread_data_tls_index, data );
 
     if (use_xim) X11DRV_SetupXIM();
-- 
2.8.1




More information about the wine-patches mailing list