winex11: Use an offscreen redirected window for child OpenGL rendering.
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 @@
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 @@
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 @@
{
wine_tsx11_lock();
pglFlush();
+ update_drawable(((Wine_GLContext*)NtCurrentTeb()->glContext)->physDev);
wine_tsx11_unlock();
}
@@ -3188,6 +3213,7 @@
drawable = get_glxdrawable(physDev);
wine_tsx11_lock();
pglXSwapBuffers(gdi_display, drawable);
+ update_drawable(physDev);
wine_tsx11_unlock();
/* FPS support */
@@ -3249,6 +3275,16 @@
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 @@
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 @@
/* for XDG systray icons */
#define SYSTEM_TRAY_REQUEST_DOCK 0
+extern int usexcomposite;
+
/***********************************************************************
* is_window_managed
*
@@ -172,16 +175,123 @@
*/
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 @@
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 @@
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 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 );