OpenGL child windows (SketchUp)

Roderick Colenbrander thunderbird2k at gmail.com
Fri Feb 17 15:13:10 CST 2012


Hi,

I have had a quick look. Although I'm not a big fan of the old OpenML
extension. It would be really nice if DRI drivers could be fixed to
get a proper glXWaitGL and friends. It still feels like the OpenML
extension does a little more than we really need. Since all DRI2
drivers seem to support it, we could just use it. I think your code
looks reasonable. In the fallback path we could use glXWaitGL instead
of glFinish, but glFinish is nearly the same anyway. Have you done any
benchmarks?

Single buffered applications are an issue, but from what I remember
Windows Vista and up have the same problem. There were some articles
on what happens on recent Windows versions and I think it was similar
to what we are doing with glFlush/glFinish. I'm not sure if we should
complicate the code too much for those usually old applications.

Roderick

On Thu, Feb 16, 2012 at 6:45 AM, Brian Bloniarz
<brian.bloniarz at gmail.com> wrote:
> Below is a patch which fixes the visuals for me, it simply uses
> glXWaitForSbcOML, falling back to glFinish if that's not supported.
>
> Partway through coding this up, I was thinking that maybe listening
> for damage events would be more natural. One reason: the current
> code is probably imperfect for single-buffered contexts. The window will get
> redrawn any time glFlush or glFinish was called (flush_gl_drawable is
> called inside both), but really apps might expect that a single-buffered
> window get updated whenever rendering finishes. Damage is naturally
> asynchronous (which might avoid a performance hit). I also wonder whether
> vsync is easier to make work with that kind of flow (how do compositing
> window managers accomplish this? they've got the same problem).
>
> All the same, that might be a more invasive thing (i.e. can you do it
> asynchronously? hook into the event loop and intercept damage events).
>
> diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c
> index e8d0f89..c541044 100644
> --- a/dlls/winex11.drv/opengl.c
> +++ b/dlls/winex11.drv/opengl.c
> @@ -256,6 +256,9 @@ MAKE_FUNCPTR(glXGetCurrentReadDrawable)
>  static GLXContext (*pglXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
>  static void* (*pglXGetProcAddressARB)(const GLubyte *);
>  static int   (*pglXSwapIntervalSGI)(int);
> +static int   (*pglXSwapIntervalSGI)(int);
> +static BOOL  (*pglXWaitForSbcOML)(Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);
> +static BOOL  (*pglXGetSyncValuesOML)(Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);
>
>  /* ATI GLX Extensions */
>  static BOOL  (*pglXBindTexImageATI)(Display *dpy, GLXPbuffer pbuffer, int buffer);
> @@ -602,6 +605,11 @@ static BOOL has_opengl(void)
>         pglXCopySubBufferMESA = pglXGetProcAddressARB((const GLubyte *) "glXCopySubBufferMESA");
>     }
>
> +    if(glxRequireExtension("GLX_OML_sync_control")) {
> +        pglXWaitForSbcOML = pglXGetProcAddressARB((const GLubyte *) "glXWaitForSbcOML");
> +        pglXGetSyncValuesOML = pglXGetProcAddressARB((const GLubyte *) "glXGetSyncValuesOML");
> +    }
> +
>     X11DRV_WineGL_LoadExtensions();
>
>     wine_tsx11_unlock();
> @@ -2281,6 +2289,11 @@ static void WINAPI X11DRV_wglGetIntegerv(GLenum pname, GLint* params)
>     wine_tsx11_unlock();
>  }
>
> +/* For offscreen-rendered (child) windows, this copies the window
> + * content into to the onscreen window. The caller must have
> + * performed any OpenGL flushing to ensure the gl_drawable is
> + * up-to-date
> + */
>  void flush_gl_drawable(X11DRV_PDEVICE *physDev)
>  {
>     int w, h;
> @@ -2295,10 +2308,7 @@ void flush_gl_drawable(X11DRV_PDEVICE *physDev)
>         Drawable src = physDev->pixmap;
>         if(!src) src = physDev->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 */
>         wine_tsx11_lock();
> -        XFlush(gdi_display);
>         XSetFunction(gdi_display, physDev->gc, GXcopy);
>         XCopyArea(gdi_display, src, physDev->drawable, physDev->gc, 0, 0, w, h,
>                   physDev->dc_rect.left, physDev->dc_rect.top);
> @@ -3857,6 +3867,8 @@ BOOL X11DRV_SwapBuffers(PHYSDEV dev)
>   wine_tsx11_lock();
>   sync_context(ctx);
>   if(physDev->pixmap) {
> +      /* Child window w/ pixmap rendering
> +       * (composite extension unavailable) */
>       if(pglXCopySubBufferMESA) {
>           int w = physDev->dc_rect.right - physDev->dc_rect.left;
>           int h = physDev->dc_rect.bottom - physDev->dc_rect.top;
> @@ -3867,14 +3879,33 @@ BOOL X11DRV_SwapBuffers(PHYSDEV dev)
>           pglFlush();
>           if(w > 0 && h > 0)
>               pglXCopySubBufferMESA(gdi_display, drawable, 0, 0, w, h);
> +      } else {
> +          pglXSwapBuffers(gdi_display, drawable);
>       }
> -      else
> +      flush_gl_drawable(physDev);
> +  } else if(physDev->gl_drawable) {
> +      /* Composite-redirected child window. We must wait for the buffer swap
> +       * since flush_gl_drawable will be copying out the window contents. */
> +      if(pglXWaitForSbcOML) {
> +          /* Wait for swap buffer with GLX_OML_sync_control extension,
> +           * if it's supported. Note that DRI-based renderers like r600g
> +           * support this extension and wait for swap on glFinish(). */
> +          int64_t ust, msc, sbc;
> +          pglXGetSyncValuesOML(gdi_display, drawable, &ust, &msc, &sbc);
>           pglXSwapBuffers(gdi_display, drawable);
> -  }
> -  else
> +          pglXWaitForSbcOML(gdi_display, drawable, sbc+1, &ust, &msc, &sbc);
> +      } else {
> +          /* No GLX_OML_swap_method support, just assume that glFinish() will
> +           * wait for the swap. This works on nv & fglrx. */
> +          pglXSwapBuffers(gdi_display, drawable);
> +          pglFinish();
> +      }
> +      flush_gl_drawable(physDev);
> +  } else {
> +      /* normal fullscreen window */
>       pglXSwapBuffers(gdi_display, drawable);
> +  }
>
> -  flush_gl_drawable(physDev);
>   wine_tsx11_unlock();
>
>   /* FPS support */



More information about the wine-devel mailing list