[Mesa-dev] [RFC 1/2] glx|egl: allow to test if glthread is safe enough on X11 platform

Gregory Hainaut gregory.hainaut at gmail.com
Fri Apr 28 21:11:32 UTC 2017


I extended the struct __DRIbackgroundCallableExtensionRec because
the other function pointer is already related for glthread.

DRI2/DRI3 glx code path check that display can be locked (basically
XInitThread was called)

EGL code path is more tricky as we don't want to pull X11 header. Instead
the code will assume that it is safe if X11 isn't used or there is no display
(i.e. 100% XCB)

The new function will be used in the next commit

Signed-off-by: Gregory Hainaut <gregory.hainaut at gmail.com>
---
 include/GL/internal/dri_interface.h |  9 +++++++++
 src/egl/drivers/dri2/egl_dri2.c     | 30 ++++++++++++++++++++++++++++++
 src/glx/dri2_glx.c                  |  9 +++++++++
 src/glx/dri3_glx.c                  |  8 ++++++++
 4 files changed, 56 insertions(+)

diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h
index 86efd1bdc9..28a52ccdb9 100644
--- a/include/GL/internal/dri_interface.h
+++ b/include/GL/internal/dri_interface.h
@@ -1713,13 +1713,22 @@ struct __DRIbackgroundCallableExtensionRec {
     * non-background thread (i.e. a thread that has already been bound to a
     * context using __DRIcoreExtensionRec::bindContext()); when this happens,
     * the \c loaderPrivate pointer must be equal to the pointer that was
     * passed to the driver when the currently bound context was created.
     *
     * This call should execute quickly enough that the driver can call it with
     * impunity whenever a background thread starts performing drawing
     * operations (e.g. it should just set a thread-local variable).
     */
    void (*setBackgroundContext)(void *loaderPrivate);
+   /**
+    * Indicate that it is multithread safe to use glthread. Typically
+    * XInitThread was called in GLX setup.
+    *
+    * \param loaderPrivate is the value that was passed to to the driver when
+    * the context was created.  This can be used by the loader to identify
+    * which context any callbacks are associated with.
+    */
+   GLboolean (*isGlThreadSafe)(void *loaderPrivate);
 };
 
 #endif
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 2cab7d00c1..df2db97bcf 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -85,24 +85,54 @@
 
 static void
 dri_set_background_context(void *loaderPrivate)
 {
    _EGLContext *ctx = _eglGetCurrentContext();
    _EGLThreadInfo *t = _eglGetCurrentThread();
 
    _eglBindContextToThread(ctx, t);
 }
 
+static GLboolean
+dri_is_glthread_safe(void *loaderPrivate)
+{
+#ifdef HAVE_X11_PLATFORM
+   struct dri2_egl_surface *dri2_surf = loaderPrivate;
+   _EGLDisplay *display =  dri2_surf->base.Resource.Display;
+   Display *dpy;
+
+   // Only the libX11 isn't safe
+   if (display->Platform != _EGL_PLATFORM_X11)
+      return true;
+
+   // Will use pure XCB so no libX11 here either
+   if (display->PlatformDisplay == NULL)
+      return true;
+
+   // In an ideal world we would check the X11 lock pointer
+   // (display->PlatformDisplay->lock_fns). Unfortunately it
+   // requires to know the full type. And we don't want to bring X11
+   // headers here.
+   //
+   // So let's assume an unsafe behavior. Modern EGL code shouldn't use
+   // libX11 anyway.
+   return false;
+#else
+   return true;
+#endif
+}
+
 const __DRIbackgroundCallableExtension background_callable_extension = {
    .base = { __DRI_BACKGROUND_CALLABLE, 1 },
 
    .setBackgroundContext = dri_set_background_context,
+   .isGlThreadSafe       = dri_is_glthread_safe,
 };
 
 const __DRIuseInvalidateExtension use_invalidate = {
    .base = { __DRI_USE_INVALIDATE, 1 }
 };
 
 EGLint dri2_to_egl_attribute_map[] = {
    0,
    EGL_BUFFER_SIZE,                /* __DRI_ATTRIB_BUFFER_SIZE */
    EGL_LEVEL,                        /* __DRI_ATTRIB_LEVEL */
diff --git a/src/glx/dri2_glx.c b/src/glx/dri2_glx.c
index 145f44d6e8..8f4d2f027f 100644
--- a/src/glx/dri2_glx.c
+++ b/src/glx/dri2_glx.c
@@ -946,20 +946,28 @@ dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
   return priv->swap_interval;
 }
 
 static void
 driSetBackgroundContext(void *loaderPrivate)
 {
    struct dri2_context *pcp = (struct dri2_context *) loaderPrivate;
    __glXSetCurrentContext(&pcp->base);
 }
 
+static GLboolean
+driIsGlThreadSafe(void *loaderPrivate)
+{
+   struct dri2_context *pcp = (struct dri2_context *) loaderPrivate;
+   return pcp->base.psc->dpy->lock_fns != NULL;
+}
+
+
 static const __DRIdri2LoaderExtension dri2LoaderExtension = {
    .base = { __DRI_DRI2_LOADER, 3 },
 
    .getBuffers              = dri2GetBuffers,
    .flushFrontBuffer        = dri2FlushFrontBuffer,
    .getBuffersWithFormat    = dri2GetBuffersWithFormat,
 };
 
 static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
    .base = { __DRI_DRI2_LOADER, 3 },
@@ -970,20 +978,21 @@ static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
 };
 
 static const __DRIuseInvalidateExtension dri2UseInvalidate = {
    .base = { __DRI_USE_INVALIDATE, 1 }
 };
 
 static const __DRIbackgroundCallableExtension driBackgroundCallable = {
    .base = { __DRI_BACKGROUND_CALLABLE, 1 },
 
    .setBackgroundContext    = driSetBackgroundContext,
+   .isGlThreadSafe          = driIsGlThreadSafe,
 };
 
 _X_HIDDEN void
 dri2InvalidateBuffers(Display *dpy, XID drawable)
 {
    __GLXDRIdrawable *pdraw =
       dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
    struct dri2_screen *psc;
    struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
 
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
index e1dc5aa4a8..cebf22059d 100644
--- a/src/glx/dri3_glx.c
+++ b/src/glx/dri3_glx.c
@@ -496,37 +496,45 @@ dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
    loader_dri3_wait_gl(draw);
 }
 
 static void
 dri_set_background_context(void *loaderPrivate)
 {
    struct dri3_context *pcp = (struct dri3_context *)loaderPrivate;
    __glXSetCurrentContext(&pcp->base);
 }
 
+static GLboolean
+dri_is_glthread_safe(void *loaderPrivate)
+{
+   struct dri3_context *pcp = (struct dri3_context *) loaderPrivate;
+   return pcp->base.psc->dpy->lock_fns != NULL;
+}
+
 /* The image loader extension record for DRI3
  */
 static const __DRIimageLoaderExtension imageLoaderExtension = {
    .base = { __DRI_IMAGE_LOADER, 1 },
 
    .getBuffers          = loader_dri3_get_buffers,
    .flushFrontBuffer    = dri3_flush_front_buffer,
 };
 
 const __DRIuseInvalidateExtension dri3UseInvalidate = {
    .base = { __DRI_USE_INVALIDATE, 1 }
 };
 
 static const __DRIbackgroundCallableExtension driBackgroundCallable = {
    .base = { __DRI_BACKGROUND_CALLABLE, 1 },
 
    .setBackgroundContext = dri_set_background_context,
+   .isGlThreadSafe       = dri_is_glthread_safe,
 };
 
 static const __DRIextension *loader_extensions[] = {
    &imageLoaderExtension.base,
    &dri3UseInvalidate.base,
    &driBackgroundCallable.base,
    NULL
 };
 
 /** dri3_swap_buffers
-- 
2.11.0



More information about the mesa-dev mailing list