From 00633e37bcc8da1032f34ea2d87814739de07db4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Sep 2007 22:43:38 -0700 Subject: [PATCH] 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(+) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 8c3496d94f2..eba5c263f23 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 f4be4a58db8..e2cb90cb6aa 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 e26835d1729..36c58531b38 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 ); -- 2.11.4.GIT