[PATCH] winex11: use GLX 1.3 glX{Create|Destroy}Window calls

Miklós Máté mtmkls at gmail.com
Sat May 7 18:37:25 CDT 2016


And convert Pixmap handling from GLX 1.0 to 1.3 while we're at it

Motivation:
With DRI it's the client-side GLX code of Mesa that stores the state about
the drawables. It doesn't know about XCreateWindow and XDestroyWindow
calls, because it's completely separate from xlib. Unless glXCreateWindow
was called, it only assigns DRI resources to the GLX object while it's
bound to a context to avoid resource leak.

Most applications are fine with this -- in fact practically nobody calls
glXCreateWindow. Star Wars: Knights of the Old Republic, however, switches
back-and-forth between the window and a series of pbuffers when drawing
its post-process effects. Without glXCreateWindow the window loses its
contents when a pbuffer is made current, and thus the followings happen:
- all the dynamic objects disappear when soft shadows are enabled, as they
  are drawn after the shadows, and they fail depth check, because the newly
  allocated depth buffer is all zeroes (the color buffer keeps its contents
  with DRI2, because it gets reallocated at the same place, but not
  anymore with DRI3)
- MSAA is completely broken when post-process is enabled
This patch fixes both of the above issues in SW:KotOR.

Signed-off-by: Miklós Máté <mtmkls at gmail.com>
---
 dlls/winex11.drv/opengl.c | 137 +++++++++++++++++++++++++---------------------
 1 file changed, 76 insertions(+), 61 deletions(-)

diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c
index 0f7534e..90cd39d 100644
--- a/dlls/winex11.drv/opengl.c
+++ b/dlls/winex11.drv/opengl.c
@@ -254,11 +254,11 @@ enum dc_gl_type
 struct gl_drawable
 {
     enum dc_gl_type                type;         /* type of GL surface */
-    Drawable                       drawable;     /* drawable for rendering to the client area */
+    Drawable                       xdrawable;    /* drawable for rendering to the client area */
+    GLXDrawable                    glxdrawable;  /* drawable for rendering with GL */
     Pixmap                         pixmap;       /* base pixmap if drawable is a GLXPixmap */
     Colormap                       colormap;     /* colormap used for the drawable */
     const struct wgl_pixel_format *format;       /* pixel format for the drawable */
-    XVisualInfo                   *visual;       /* information about the GL visual */
     RECT                           rect;         /* drawable rect, relative to whole window drawable */
     int                            swap_interval;
     BOOL                           refresh_swap_interval;
@@ -373,8 +373,6 @@ static void (*pglXDestroyContext)( Display *dpy, GLXContext ctx );
 static Bool (*pglXMakeCurrent)( Display *dpy, GLXDrawable drawable, GLXContext ctx);
 static void (*pglXCopyContext)( Display *dpy, GLXContext src, GLXContext dst, unsigned long mask );
 static void (*pglXSwapBuffers)( Display *dpy, GLXDrawable drawable );
-static GLXPixmap (*pglXCreateGLXPixmap)( Display *dpy, XVisualInfo *visual, Pixmap pixmap );
-static void (*pglXDestroyGLXPixmap)( Display *dpy, GLXPixmap pixmap );
 static Bool (*pglXQueryExtension)( Display *dpy, int *errorb, int *event );
 static Bool (*pglXQueryVersion)( Display *dpy, int *maj, int *min );
 static Bool (*pglXIsDirect)( Display *dpy, GLXContext ctx );
@@ -397,6 +395,10 @@ static void (*pglXDestroyPbuffer)( Display *dpy, GLXPbuffer pbuf );
 static void (*pglXQueryDrawable)( Display *dpy, GLXDrawable draw, int attribute, unsigned int *value );
 static GLXContext (*pglXCreateNewContext)( Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool direct );
 static Bool (*pglXMakeContextCurrent)( Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx );
+static GLXWindow (*pglXCreateWindow)( Display *dpy, GLXFBConfig config, Window win, const int *attrib_list );
+static void (*pglXDestroyWindow)( Display *dpy, GLXWindow win );
+static GLXPixmap (*pglXCreatePixmap)( Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list );
+static void (*pglXDestroyPixmap)( Display *dpy, GLXPixmap pixmap );
 
 /* GLX Extensions */
 static GLXContext (*pglXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
@@ -624,11 +626,9 @@ static BOOL WINAPI init_opengl( INIT_ONCE *once, void *param, void **context )
     LOAD_FUNCPTR(glXChooseVisual);
     LOAD_FUNCPTR(glXCopyContext);
     LOAD_FUNCPTR(glXCreateContext);
-    LOAD_FUNCPTR(glXCreateGLXPixmap);
     LOAD_FUNCPTR(glXGetCurrentContext);
     LOAD_FUNCPTR(glXGetCurrentDrawable);
     LOAD_FUNCPTR(glXDestroyContext);
-    LOAD_FUNCPTR(glXDestroyGLXPixmap);
     LOAD_FUNCPTR(glXGetConfig);
     LOAD_FUNCPTR(glXIsDirect);
     LOAD_FUNCPTR(glXMakeCurrent);
@@ -647,6 +647,10 @@ static BOOL WINAPI init_opengl( INIT_ONCE *once, void *param, void **context )
     LOAD_FUNCPTR(glXDestroyPbuffer);
     LOAD_FUNCPTR(glXMakeContextCurrent);
     LOAD_FUNCPTR(glXGetFBConfigs);
+    LOAD_FUNCPTR(glXCreateWindow);
+    LOAD_FUNCPTR(glXDestroyWindow);
+    LOAD_FUNCPTR(glXCreatePixmap);
+    LOAD_FUNCPTR(glXDestroyPixmap);
 #undef LOAD_FUNCPTR
 
 /* It doesn't matter if these fail. They'll only be used if the driver reports
@@ -1229,7 +1233,7 @@ static inline void sync_context(struct wgl_context *context)
     }
 }
 
-static BOOL set_swap_interval(Drawable drawable, int interval)
+static BOOL set_swap_interval(GLXDrawable drawable, int interval)
 {
     BOOL ret = TRUE;
 
@@ -1310,17 +1314,17 @@ static void free_gl_drawable( struct gl_drawable *gl )
     switch (gl->type)
     {
     case DC_GL_CHILD_WIN:
-        XDestroyWindow( gdi_display, gl->drawable );
+        pglXDestroyWindow( gdi_display, gl->glxdrawable );
+        XDestroyWindow( gdi_display, gl->xdrawable );
         XFreeColormap( gdi_display, gl->colormap );
         break;
     case DC_GL_PIXMAP_WIN:
-        pglXDestroyGLXPixmap( gdi_display, gl->drawable );
+        pglXDestroyPixmap( gdi_display, gl->glxdrawable );
         XFreePixmap( gdi_display, gl->pixmap );
         break;
     default:
         break;
     }
-    if (gl->visual) XFree( gl->visual );
     HeapFree( GetProcessHeap(), 0, gl );
 }
 
@@ -1330,7 +1334,11 @@ static void free_gl_drawable( struct gl_drawable *gl )
  */
 static BOOL create_gl_drawable( HWND hwnd, struct gl_drawable *gl )
 {
-    gl->drawable = 0;
+    XVisualInfo *visual;
+
+    gl->xdrawable = 0;
+    gl->glxdrawable = 0;
+    visual = pglXGetVisualFromFBConfig( gdi_display, gl->format->fbconfig );
 
     if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())  /* top-level window */
     {
@@ -1339,7 +1347,8 @@ static BOOL create_gl_drawable( HWND hwnd, struct gl_drawable *gl )
         if (data)
         {
             gl->type = DC_GL_WINDOW;
-            gl->drawable = create_client_window( data, gl->visual );
+            gl->xdrawable = create_client_window( data, visual );
+            gl->glxdrawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->xdrawable, NULL );
             release_win_data( data );
         }
     }
@@ -1356,23 +1365,24 @@ static BOOL create_gl_drawable( HWND hwnd, struct gl_drawable *gl )
                                          InputOutput, default_visual.visual, CWOverrideRedirect, &attrib );
             XMapWindow( gdi_display, dummy_parent );
         }
-        gl->colormap = XCreateColormap(gdi_display, dummy_parent, gl->visual->visual,
-                                       (gl->visual->class == PseudoColor ||
-                                        gl->visual->class == GrayScale ||
-                                        gl->visual->class == DirectColor) ?
+        gl->colormap = XCreateColormap(gdi_display, dummy_parent, visual->visual,
+                                       (visual->class == PseudoColor ||
+                                        visual->class == GrayScale ||
+                                        visual->class == DirectColor) ?
                                        AllocAll : AllocNone);
         attrib.colormap = gl->colormap;
         XInstallColormap(gdi_display, attrib.colormap);
 
         gl->type = DC_GL_CHILD_WIN;
-        gl->drawable = XCreateWindow( gdi_display, dummy_parent, 0, 0,
+        gl->xdrawable = XCreateWindow( gdi_display, dummy_parent, 0, 0,
                                       gl->rect.right - gl->rect.left, gl->rect.bottom - gl->rect.top,
-                                      0, gl->visual->depth, InputOutput, gl->visual->visual,
+                                      0, visual->depth, InputOutput, visual->visual,
                                       CWColormap | CWOverrideRedirect, &attrib );
-        if (gl->drawable)
+        if (gl->xdrawable)
         {
-            pXCompositeRedirectWindow(gdi_display, gl->drawable, CompositeRedirectManual);
-            XMapWindow(gdi_display, gl->drawable);
+            gl->glxdrawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->xdrawable, NULL );
+            pXCompositeRedirectWindow(gdi_display, gl->xdrawable, CompositeRedirectManual);
+            XMapWindow(gdi_display, gl->xdrawable);
         }
         else XFreeColormap( gdi_display, gl->colormap );
     }
@@ -1384,17 +1394,17 @@ static BOOL create_gl_drawable( HWND hwnd, struct gl_drawable *gl )
         gl->type = DC_GL_PIXMAP_WIN;
         gl->pixmap = XCreatePixmap( gdi_display, root_window,
                                     gl->rect.right - gl->rect.left, gl->rect.bottom - gl->rect.top,
-                                    gl->visual->depth );
+                                    visual->depth );
         if (gl->pixmap)
         {
-            gl->drawable = pglXCreateGLXPixmap( gdi_display, gl->visual, gl->pixmap );
-            if (!gl->drawable) XFreePixmap( gdi_display, gl->pixmap );
+            gl->glxdrawable = pglXCreatePixmap( gdi_display, gl->format->fbconfig, gl->pixmap, NULL );
+            if (!gl->glxdrawable) XFreePixmap( gdi_display, gl->pixmap );
         }
     }
 
-    if (gl->drawable)
+    if (gl->xdrawable)
         gl->refresh_swap_interval = TRUE;
-    return gl->drawable != 0;
+    return gl->xdrawable != 0;
 }
 
 
@@ -1404,6 +1414,7 @@ static BOOL create_gl_drawable( HWND hwnd, struct gl_drawable *gl )
 static BOOL set_win_format( HWND hwnd, const struct wgl_pixel_format *format )
 {
     struct gl_drawable *gl, *prev;
+    XVisualInfo *visual;
 
     gl = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*gl) );
     /* Default GLX and WGL swap interval is 1, but in case of glXSwapIntervalSGI
@@ -1412,8 +1423,8 @@ static BOOL set_win_format( HWND hwnd, const struct wgl_pixel_format *format )
     gl->swap_interval = 1;
     gl->refresh_swap_interval = TRUE;
     gl->format = format;
-    gl->visual = pglXGetVisualFromFBConfig( gdi_display, format->fbconfig );
-    if (!gl->visual)
+    visual = pglXGetVisualFromFBConfig( gdi_display, format->fbconfig );
+    if (!visual)
     {
         HeapFree( GetProcessHeap(), 0, gl );
         return FALSE;
@@ -1425,13 +1436,13 @@ static BOOL set_win_format( HWND hwnd, const struct wgl_pixel_format *format )
 
     if (!create_gl_drawable( hwnd, gl ))
     {
-        XFree( gl->visual );
+        XFree( visual );
         HeapFree( GetProcessHeap(), 0, gl );
         return FALSE;
     }
 
     TRACE( "created GL drawable %lx for win %p %s\n",
-           gl->drawable, hwnd, debugstr_fbconfig( format->fbconfig ));
+           gl->glxdrawable, hwnd, debugstr_fbconfig( format->fbconfig ));
 
     XFlush( gdi_display );
 
@@ -1502,6 +1513,7 @@ void sync_gl_drawable( HWND hwnd, const RECT *visible_rect, const RECT *client_r
     Pixmap pix;
     int mask = 0;
     XWindowChanges changes;
+    XVisualInfo *visual = NULL;
 
     changes.width  = min( max( 1, client_rect->right - client_rect->left ), 65535 );
     changes.height = min( max( 1, client_rect->bottom - client_rect->top ), 65535 );
@@ -1511,38 +1523,41 @@ void sync_gl_drawable( HWND hwnd, const RECT *visible_rect, const RECT *client_r
     if (changes.width  != gl->rect.right - gl->rect.left) mask |= CWWidth;
     if (changes.height != gl->rect.bottom - gl->rect.top) mask |= CWHeight;
 
-    TRACE( "setting drawable %lx size %dx%d\n", gl->drawable, changes.width, changes.height );
+    TRACE( "setting drawable %lx size %dx%d\n", gl->xdrawable, changes.width, changes.height );
 
     switch (gl->type)
     {
     case DC_GL_CHILD_WIN:
-        if (mask) XConfigureWindow( gdi_display, gl->drawable, mask, &changes );
+        if (mask) XConfigureWindow( gdi_display, gl->xdrawable, mask, &changes );
         break;
     case DC_GL_PIXMAP_WIN:
         if (!mask) break;
-        pix = XCreatePixmap(gdi_display, root_window, changes.width, changes.height, gl->visual->depth);
+        visual = pglXGetVisualFromFBConfig( gdi_display, gl->format->fbconfig );
+        pix = XCreatePixmap(gdi_display, root_window, changes.width, changes.height, visual->depth);
         if (!pix) goto done;
-        glxp = pglXCreateGLXPixmap(gdi_display, gl->visual, pix);
+        glxp = pglXCreatePixmap(gdi_display, gl->format->fbconfig, pix, NULL);
         if (!glxp)
         {
             XFreePixmap(gdi_display, pix);
             goto done;
         }
-        mark_drawable_dirty(gl->drawable, glxp);
+        mark_drawable_dirty(gl->glxdrawable, glxp);
         XFlush( gdi_display );
 
         XFreePixmap(gdi_display, gl->pixmap);
-        pglXDestroyGLXPixmap(gdi_display, gl->drawable);
-        TRACE( "Recreated GL drawable %lx to replace %lx\n", glxp, gl->drawable );
+        pglXDestroyPixmap(gdi_display, gl->glxdrawable);
+        TRACE( "Recreated GL drawable %lx to replace %lx\n", glxp, gl->glxdrawable );
 
         gl->pixmap = pix;
-        gl->drawable = glxp;
+        gl->glxdrawable = glxp;
         break;
     default:
         break;
     }
     SetRect( &gl->rect, 0, 0, changes.width, changes.height );
 done:
+    if (visual)
+        XFree( visual );
     release_gl_drawable( gl );
 }
 
@@ -1557,21 +1572,22 @@ void set_gl_drawable_parent( HWND hwnd, HWND parent )
 
     if (!(gl = get_gl_drawable( hwnd, 0 ))) return;
 
-    TRACE( "setting drawable %lx parent %p\n", gl->drawable, parent );
+    TRACE( "setting drawable %lx parent %p\n", gl->glxdrawable, parent );
 
-    old_drawable = gl->drawable;
+    old_drawable = gl->glxdrawable;
     switch (gl->type)
     {
     case DC_GL_WINDOW:
         break;
     case DC_GL_CHILD_WIN:
         if (parent != GetDesktopWindow()) goto done;
-        XDestroyWindow( gdi_display, gl->drawable );
+        pglXDestroyWindow( gdi_display, gl->glxdrawable );
+        XDestroyWindow( gdi_display, gl->xdrawable );
         XFreeColormap( gdi_display, gl->colormap );
         break;
     case DC_GL_PIXMAP_WIN:
         if (parent != GetDesktopWindow()) goto done;
-        pglXDestroyGLXPixmap( gdi_display, gl->drawable );
+        pglXDestroyPixmap( gdi_display, gl->glxdrawable );
         XFreePixmap( gdi_display, gl->pixmap );
         break;
     default:
@@ -1582,12 +1598,11 @@ void set_gl_drawable_parent( HWND hwnd, HWND parent )
     {
         XDeleteContext( gdi_display, (XID)hwnd, gl_hwnd_context );
         release_gl_drawable( gl );
-        XFree( gl->visual );
         HeapFree( GetProcessHeap(), 0, gl );
         __wine_set_pixel_format( hwnd, 0 );
         return;
     }
-    mark_drawable_dirty( old_drawable, gl->drawable );
+    mark_drawable_dirty( old_drawable, gl->glxdrawable );
 
 done:
     release_gl_drawable( gl );
@@ -1874,17 +1889,17 @@ static BOOL glxdrv_wglMakeCurrent(HDC hdc, struct wgl_context *ctx)
             goto done;
         }
 
-        TRACE("hdc %p drawable %lx fmt %p ctx %p %s\n", hdc, gl->drawable, gl->format, ctx->ctx,
+        TRACE("hdc %p drawable %lx fmt %p ctx %p %s\n", hdc, gl->glxdrawable, gl->format, ctx->ctx,
               debugstr_fbconfig( gl->format->fbconfig ));
 
-        ret = pglXMakeCurrent(gdi_display, gl->drawable, ctx->ctx);
+        ret = pglXMakeCurrent(gdi_display, gl->glxdrawable, ctx->ctx);
         if (ret)
         {
             NtCurrentTeb()->glContext = ctx;
             ctx->has_been_current = TRUE;
             ctx->hdc = hdc;
-            ctx->drawables[0] = gl->drawable;
-            ctx->drawables[1] = gl->drawable;
+            ctx->drawables[0] = gl->glxdrawable;
+            ctx->drawables[1] = gl->glxdrawable;
             ctx->refresh_drawables = FALSE;
             goto done;
         }
@@ -1919,14 +1934,14 @@ static BOOL X11DRV_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct
     if ((draw_gl = get_gl_drawable( WindowFromDC( draw_hdc ), draw_hdc )))
     {
         read_gl = get_gl_drawable( WindowFromDC( read_hdc ), read_hdc );
-        ret = pglXMakeContextCurrent(gdi_display, draw_gl->drawable,
-                                     read_gl ? read_gl->drawable : 0, ctx->ctx);
+        ret = pglXMakeContextCurrent(gdi_display, draw_gl->glxdrawable,
+                                     read_gl ? read_gl->glxdrawable : 0, ctx->ctx);
         if (ret)
         {
             ctx->has_been_current = TRUE;
             ctx->hdc = draw_hdc;
-            ctx->drawables[0] = draw_gl->drawable;
-            ctx->drawables[1] = read_gl ? read_gl->drawable : 0;
+            ctx->drawables[0] = draw_gl->glxdrawable;
+            ctx->drawables[1] = read_gl ? read_gl->glxdrawable : 0;
             ctx->refresh_drawables = FALSE;
             NtCurrentTeb()->glContext = ctx;
             goto done;
@@ -1999,7 +2014,7 @@ static void wglFinish(void)
         switch (gl->type)
         {
         case DC_GL_PIXMAP_WIN: escape.gl_drawable = gl->pixmap; break;
-        case DC_GL_CHILD_WIN:  escape.gl_drawable = gl->drawable; break;
+        case DC_GL_CHILD_WIN:  escape.gl_drawable = gl->xdrawable; break;
         default: break;
         }
         sync_context(ctx);
@@ -2024,7 +2039,7 @@ static void wglFlush(void)
         switch (gl->type)
         {
         case DC_GL_PIXMAP_WIN: escape.gl_drawable = gl->pixmap; break;
-        case DC_GL_CHILD_WIN:  escape.gl_drawable = gl->drawable; break;
+        case DC_GL_CHILD_WIN:  escape.gl_drawable = gl->xdrawable; break;
         default: break;
         }
         sync_context(ctx);
@@ -2368,7 +2383,7 @@ static HDC X11DRV_wglGetPbufferDCARB( struct wgl_pbuffer *object )
         return 0;
     }
     gl->type = DC_GL_PBUFFER;
-    gl->drawable = object->drawable;
+    gl->glxdrawable = object->drawable;
     gl->format = object->fmt;
 
     EnterCriticalSection( &context_section );
@@ -3076,7 +3091,7 @@ static BOOL X11DRV_wglSwapIntervalEXT(int interval)
         return FALSE;
     }
 
-    ret = set_swap_interval(gl->drawable, interval);
+    ret = set_swap_interval(gl->glxdrawable, interval);
     gl->refresh_swap_interval = FALSE;
     if (ret)
         gl->swap_interval = interval;
@@ -3300,7 +3315,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc )
 
     if (gl->refresh_swap_interval)
     {
-        set_swap_interval(gl->drawable, gl->swap_interval);
+        set_swap_interval(gl->glxdrawable, gl->swap_interval);
         gl->refresh_swap_interval = FALSE;
     }
 
@@ -3314,18 +3329,18 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc )
              * GLX_MESA_copy_sub_buffer doesn't. Make sure GL is flushed before
              * copying */
             pglFlush();
-            pglXCopySubBufferMESA( gdi_display, gl->drawable, 0, 0,
+            pglXCopySubBufferMESA( gdi_display, gl->glxdrawable, 0, 0,
                                    gl->rect.right - gl->rect.left, gl->rect.bottom - gl->rect.top );
             break;
         }
-        pglXSwapBuffers(gdi_display, gl->drawable);
+        pglXSwapBuffers(gdi_display, gl->glxdrawable);
         break;
     case DC_GL_CHILD_WIN:
         if (ctx) sync_context( ctx );
-        escape.gl_drawable = gl->drawable;
+        escape.gl_drawable = gl->xdrawable;
         /* fall through */
     default:
-        pglXSwapBuffers(gdi_display, gl->drawable);
+        pglXSwapBuffers(gdi_display, gl->glxdrawable);
         break;
     }
 
-- 
2.8.1




More information about the wine-patches mailing list