Hi all,
I could use a little help fixing a window lag and screen corruption issue in SketchUp: http://bugs.winehq.org/show_bug.cgi?id=25912 Long story short, I think the implementation of OpenGL child rendering needs a small update.
As a reminder, this is how an OpenGL child window is setup:
static BOOL set_win_format( HWND hwnd, XID fbconfig_id ) { gl_drawable = XCreateWindow(...); // offscreen window XCompositeRedirectWindow(..., gl_drawable, CompositeRedirectManual); }
Here XComposite extension is render into an offscreen window. When it's time to display, the contents of that window are copied into the visible onscreen parent window (physDev is the onscreen window, gl_drawable is the offscreen window):
BOOL X11DRV_SwapBuffers(PHYSDEV dev) { ... glXSwapBuffers(gdi_display, gl_drawable);
... /* 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, gl_drawable, physDev...); }
The XFlush() is the problem; the buffer swap must happen before the copy, and accelerated renderers wouldn't guarantee to do that on an X queue flush.
So how do you wait for a buffer swap? I wrote a test program, can you say "undefined behavior"? I tested on a few drivers:
1) ATI fglrx binary driver: glXSwapBuffers is instantaneous, existing code works fine.
2) NVidia binary driver: glXSwapBuffers is asynchronous, neither XFlush() nor XSync() is enough. Calling glXWaitGL or glFinish works.
3) Mesa DRI driver (Intel i915): glXSwapBuffers is asynchronous. None of XFlush/XSync/glXWaitX/glXWaitGL is enough. glFinish works.
4) r600g (Open Source accelerated ATI) driver: glXSwapBuffers is asynchronous. None of the flush calls wait for it (XFlush/XSync/glXWaitGL/glXWaitX/glFinish).
The last one is the tricky part -- this driver is also based on the DRI, so I'm guessing it may appear on other open-source accelerated drivers (looking at http://www.x.org/releases/current/doc/dri2proto/dri2proto.txt suggests that this is new behavior as of 1.99.2)
So how to come up with a common fix? I could think of 3 possibilities:
1) Use the GLX_OML_sync_control extension, it has an explicit call to wait for a buffer swap. Not supported by NV or fglrx, but we could fallback to glXWaitGL on those drivers. Probably simplest.
2) Use the X Damage extension, wait for an XDamageNotify event before copying. This should work everywhere, all drivers probably implement damage so that compositing window managers can use it.
3) Talk to the DRI people, maybe glXWaitGL should't return when there's a pending a buffer swap. The GLX spec seems to say it should wait, but it's a grey area and the Composite extension was designed much later. Not a quick fix.
Any ideas or thoughts? If I hear nothing, I can code up a patch that does (1), but it'd be great to hear from some people who know this area well.
Thanks, Brian Bloniarz