Chris Robinson : winex11: Use an offscreen redirected window for child OpenGL rendering.

Alexandre Julliard julliard at winehq.org
Wed Oct 3 06:08:18 CDT 2007


Module: wine
Branch: master
Commit: 00633e37bcc8da1032f34ea2d87814739de07db4
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=00633e37bcc8da1032f34ea2d87814739de07db4

Author: Chris Robinson <chris.kcat at gmail.com>
Date:   Tue Sep 25 22:43:38 2007 -0700

winex11: Use an offscreen redirected window for child OpenGL rendering.

---

 dlls/winex11.drv/opengl.c |   41 +++++++++++++++
 dlls/winex11.drv/window.c |  122 +++++++++++++++++++++++++++++++++++++++++++++
 dlls/winex11.drv/x11drv.h |    1 +
 3 files changed, 164 insertions(+), 0 deletions(-)

diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c
index 8c3496d..eba5c26 100644
--- a/dlls/winex11.drv/opengl.c
+++ b/dlls/winex11.drv/opengl.c
@@ -1393,6 +1393,8 @@ BOOL X11DRV_SetPixelFormat(X11DRV_PDEVICE *physDev,
             ERR("Couldn't set format of the window, returning failure\n");
             return FALSE;
         }
+
+        physDev->gl_drawable = X11DRV_get_gl_drawable(hwnd);
     }
 
   physDev->current_pf = iPixelFormat;
@@ -1914,10 +1916,32 @@ static void WINAPI X11DRV_wglGetIntegerv(GLenum pname, GLint* params)
     wine_tsx11_unlock();
 }
 
+static inline void update_drawable(X11DRV_PDEVICE *physDev)
+{
+    int w, h;
+
+    if(!physDev->gl_drawable)
+        return;
+
+    w = physDev->dc_rect.right - physDev->dc_rect.left;
+    h = physDev->dc_rect.bottom - physDev->dc_rect.top;
+
+    if(w > 0 && h > 0) {
+        /* The GL drawable may be lagged behind if we don't flush first, so
+         * flush the display make sure we copy up-to-date data */
+        XFlush(gdi_display);
+        XCopyArea(gdi_display, physDev->gl_drawable, physDev->drawable,
+                  physDev->gc, 0, 0, w, h, physDev->dc_rect.left,
+                  physDev->dc_rect.top);
+    }
+}
+
+
 static void WINAPI X11DRV_wglFinish(void)
 {
     wine_tsx11_lock();
     pglFinish();
+    update_drawable(((Wine_GLContext*)NtCurrentTeb()->glContext)->physDev);
     wine_tsx11_unlock();
 }
 
@@ -1925,6 +1949,7 @@ static void WINAPI X11DRV_wglFlush(void)
 {
     wine_tsx11_lock();
     pglFlush();
+    update_drawable(((Wine_GLContext*)NtCurrentTeb()->glContext)->physDev);
     wine_tsx11_unlock();
 }
 
@@ -3188,6 +3213,7 @@ BOOL X11DRV_SwapBuffers(X11DRV_PDEVICE *physDev)
   drawable = get_glxdrawable(physDev);
   wine_tsx11_lock();
   pglXSwapBuffers(gdi_display, drawable);
+  update_drawable(physDev);
   wine_tsx11_unlock();
 
   /* FPS support */
@@ -3249,6 +3275,16 @@ XVisualInfo *X11DRV_setup_opengl_visual( Display *display )
     return visual;
 }
 
+XVisualInfo *visual_from_fbconfig_id( XID fbconfig_id )
+{
+    WineGLPixelFormat *fmt;
+
+    fmt = ConvertPixelFormatGLXtoWGL(gdi_display, fbconfig_id);
+    if(fmt == NULL)
+        return NULL;
+    return pglXGetVisualFromFBConfig(gdi_display, fmt->fbconfig);
+}
+
 #else  /* no OpenGL includes */
 
 int pixelformat_from_fbconfig_id(XID fbconfig_id)
@@ -3405,4 +3441,9 @@ BOOL destroy_glxpixmap(XID glxpixmap)
     return FALSE;
 }
 
+XVisualInfo *visual_from_fbconfig_id( XID fbconfig_id )
+{
+    return NULL;
+}
+
 #endif /* defined(HAVE_OPENGL) */
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index f4be4a5..e2cb90c 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -40,6 +40,7 @@
 #include "wine/unicode.h"
 
 #include "x11drv.h"
+#include "xcomposite.h"
 #include "wine/debug.h"
 #include "wine/server.h"
 #include "win.h"
@@ -63,6 +64,8 @@ static const char visual_id_prop[]    = "__wine_x11_visual_id";
 /* for XDG systray icons */
 #define SYSTEM_TRAY_REQUEST_DOCK    0
 
+extern int usexcomposite;
+
 /***********************************************************************
  *		is_window_managed
  *
@@ -172,16 +175,123 @@ void X11DRV_sync_window_style( Display *display, struct x11drv_win_data *data )
  */
 BOOL X11DRV_set_win_format( HWND hwnd, XID fbconfig_id )
 {
+    Display *display = thread_display();
     struct x11drv_win_data *data;
+    XVisualInfo *vis;
+    Drawable parent;
+    HWND next_hwnd;
+    int w, h;
 
     if (!(data = X11DRV_get_win_data(hwnd))) return FALSE;
 
+    wine_tsx11_lock();
+
+    vis = visual_from_fbconfig_id(fbconfig_id);
+    if(!vis) return FALSE;
+
+    if(data->whole_window && vis->visualid == XVisualIDFromVisual(visual))
+    {
+        TRACE("Whole window available and visual match, rendering onscreen\n");
+        goto done;
+    }
+
+    wine_tsx11_unlock();
+
+    parent = data->whole_window;
+    next_hwnd = hwnd;
+    while(!parent)
+    {
+        next_hwnd = GetAncestor(next_hwnd, GA_PARENT);
+        if(!next_hwnd)
+        {
+            ERR("Could not find parent HWND with a drawable!\n");
+            return FALSE;
+        }
+        parent = X11DRV_get_whole_window(next_hwnd);
+    }
+
+    w = data->client_rect.right - data->client_rect.left;
+    h = data->client_rect.bottom - data->client_rect.top;
+
+    if(w <= 0) w = 1;
+    if(h <= 0) h = 1;
+
+    wine_tsx11_lock();
+#ifdef SONAME_LIBXCOMPOSITE
+    if(usexcomposite)
+    {
+        XSetWindowAttributes attrib;
+
+        attrib.override_redirect = True;
+        attrib.colormap = XCreateColormap(display, parent, vis->visual,
+                                          (vis->class == PseudoColor ||
+                                           vis->class == GrayScale ||
+                                           vis->class == DirectColor) ?
+                                          AllocAll : AllocNone);
+        XInstallColormap(gdi_display, attrib.colormap);
+
+        data->gl_drawable = XCreateWindow(display, parent, -w, 0, w, h, 0,
+                                          vis->depth, InputOutput, vis->visual,
+                                          CWColormap | CWOverrideRedirect,
+                                          &attrib);
+        if(data->gl_drawable)
+        {
+            pXCompositeRedirectWindow(display, data->gl_drawable,
+                                      CompositeRedirectManual);
+            XMapWindow(display, data->gl_drawable);
+        }
+    }
+#endif
+
+    if(!data->gl_drawable)
+    {
+        ERR("Failed to create drawable for offscreen rendering\n");
+        XFree(vis);
+        wine_tsx11_unlock();
+        return FALSE;
+    }
+
+done:
+    XFree(vis);
+
+    XFlush(display);
+    wine_tsx11_unlock();
+
+    TRACE("Created GL drawable 0x%lx, using FBConfigID 0x%lx\n",
+          data->gl_drawable, fbconfig_id);
+
     data->fbconfig_id = fbconfig_id;
     SetPropA(hwnd, fbconfig_id_prop, (HANDLE)data->fbconfig_id);
+    SetPropA(hwnd, gl_drawable_prop, (HANDLE)data->gl_drawable);
     invalidate_dce( hwnd, &data->window_rect );
     return TRUE;
 }
 
+static void update_gl_drawable(Display *display, struct x11drv_win_data *data, const RECT *old_client_rect)
+{
+    int w = data->client_rect.right - data->client_rect.left;
+    int h = data->client_rect.bottom - data->client_rect.top;
+
+    if((w == old_client_rect->right - old_client_rect->left &&
+        h == old_client_rect->bottom - old_client_rect->top) ||
+       w <= 0 || h <= 0)
+    {
+        TRACE("No resize needed\n");
+        return;
+    }
+
+    TRACE("Resizing GL drawable 0x%lx to %dx%d\n", data->gl_drawable, w, h);
+#ifdef SONAME_LIBXCOMPOSITE
+    if(usexcomposite)
+    {
+        wine_tsx11_lock();
+        XMoveResizeWindow(display, data->gl_drawable, -w, 0, w, h);
+        wine_tsx11_unlock();
+        return;
+    }
+#endif
+}
+
 
 /***********************************************************************
  *              get_window_changes
@@ -726,13 +836,18 @@ void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data
     XWindowChanges changes;
     int mask;
     RECT old_whole_rect;
+    RECT old_client_rect;
 
     old_whole_rect = data->whole_rect;
     data->whole_rect = *new_whole_rect;
 
+    old_client_rect = data->client_rect;
     data->client_rect = *new_client_rect;
     OffsetRect( &data->client_rect, -data->whole_rect.left, -data->whole_rect.top );
 
+    if (data->gl_drawable)
+        update_gl_drawable(display, data, &old_client_rect);
+
     if (!data->whole_window || data->lock_changes) return;
 
     mask = get_window_changes( &changes, &old_whole_rect, &data->whole_rect );
@@ -931,6 +1046,13 @@ void X11DRV_DestroyWindow( HWND hwnd )
 
     if (!(data = X11DRV_get_win_data( hwnd ))) return;
 
+    if (data->gl_drawable)
+    {
+        wine_tsx11_lock();
+        XDestroyWindow(display, data->gl_drawable);
+        wine_tsx11_unlock();
+    }
+
     free_window_dce( data );
     destroy_whole_window( display, data );
     destroy_icon_window( display, data );
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index e26835d..36c5853 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -669,6 +669,7 @@ extern XIC X11DRV_get_ic( HWND hwnd );
 extern BOOL X11DRV_set_win_format( HWND hwnd, XID fbconfig );
 
 extern int pixelformat_from_fbconfig_id( XID fbconfig_id );
+extern XVisualInfo *visual_from_fbconfig_id( XID fbconfig_id );
 
 extern void alloc_window_dce( struct x11drv_win_data *data );
 extern void free_window_dce( struct x11drv_win_data *data );




More information about the wine-cvs mailing list