From 8502c0e92e00ee6d95d91068c944ce599c7eeaf3 Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Fri, 20 Nov 2009 19:22:17 +0100
Subject: [PATCH] mesa: Add new MESA_multithread_makecurrent extension.

This extension allows a client to bind one context in multiple threads
simultaneously.  It is then up to the client to manage synchronization of
access to the GL, just as normal multithreaded GL from multiple contexts
requires synchronization management to shared objects.
---
 docs/MESA_multithread_makecurrent.spec |   92 ++++++++++++++++++++++++++++++++
 src/glx/x11/glxcurrent.c               |   31 +++++++++--
 src/glx/x11/glxextensions.c            |    1 +
 src/glx/x11/glxextensions.h            |    3 +-
 4 files changed, 120 insertions(+), 7 deletions(-)
 create mode 100644 docs/MESA_multithread_makecurrent.spec

diff --git a/docs/MESA_multithread_makecurrent.spec b/docs/MESA_multithread_makecurrent.spec
new file mode 100644
index 0000000..4ba70ba
--- /dev/null
+++ b/docs/MESA_multithread_makecurrent.spec
@@ -0,0 +1,92 @@
+Name
+
+    MESA_multithread_makecurrent
+
+Name Strings
+
+    GLX_MESA_multithread_makecurrent
+
+Contact
+
+    Eric Anholt (eric.anholt@intel.com)
+
+Status
+
+    Not shipping.
+
+Version
+
+    Last Modified Date:  20 November 2009
+
+Number
+
+    XXX: fill me in
+
+Dependencies
+
+    OpenGL 1.0 or later is required.
+    GLX 1.3 or later is required.
+
+Overview
+
+    The GLX context setup encourages multithreaded applications to
+    create a context per thread which each operate on their own objects
+    in parallel, and leaves synchronization for shared objects up to the
+    application.
+
+    For some applications, maintaining per-thread contexts and ensuring
+    that the glFlush happens in one thread before another thread starts
+    working on that object is difficult.  For them, using the same context
+    across multiple threads and protecting its usage with a global lock is
+    both higher performance and easier to implement.  This extension gives
+    those applications that option by relaxing the context binding
+    requirements.
+
+IP Status
+
+    Open-source; freely implementable.
+
+Issues
+
+    None.
+
+New Procedures and Functions
+
+    None.
+
+New Tokens
+
+    None.
+
+Additions to Chapter 3 of the GLX 1.3 Specification (Functions and Errors)
+
+    Change section 3.3.7 Rendering Contexts from:
+	If ctx is current to some other thread, then
+	glXMakeContextCurrent will generate a BadAccess error.
+
+    to:
+	If GLX_MESA_multithread_make_current is not supported and ctx is
+	current to some other thread, then glXMakeCurrentContext will
+	generate a BadAccess error.  If GLX_MESA_multithread_make_current
+	is supported, then a BadAccess error will only be generated if
+	draw does not match the context's draw, read does not match the
+	context's read, or dpy does not match the context's dpy.
+
+GLX Protocol
+
+    None.  The GLX extension is client-side.
+
+Errors
+
+    BadAccess - returned if the context is bound to another thread and
+    the drawable doesn't match the current draw and read drawable of the
+    context.
+
+New State
+
+    None.
+
+Revision History
+
+    20 November 2009 Eric Anholt - initial specification
+
diff --git a/src/glx/x11/glxcurrent.c b/src/glx/x11/glxcurrent.c
index f1e3e16..72c8f45 100644
--- a/src/glx/x11/glxcurrent.c
+++ b/src/glx/x11/glxcurrent.c
@@ -331,6 +331,7 @@ MakeContextCurrent(Display * dpy, GLXDrawable draw,
    const CARD8 oldOpcode = ((gc == oldGC) || (oldGC == &dummyContext))
       ? opcode : __glXSetupForCommand(oldGC->currentDpy);
    Bool bindReturnValue;
+   Bool need_bindcontext = True;
    __GLXattribute *state;
 
    if (!opcode || !oldOpcode) {
@@ -357,15 +358,31 @@ MakeContextCurrent(Display * dpy, GLXDrawable draw,
 
    _glapi_check_multithread();
 
-   if (gc != NULL && gc->thread_id != 0 && gc->thread_id != _glthread_GetID()) {
-      __glXGenerateError(dpy, gc, gc->xid,
-                         BadAccess, X_GLXMakeContextCurrent);
-      return False;
+   if (gc != NULL && gc->thread_id != 0) {
+      if (!__glXExtensionBitIsEnabled(gc->psc,
+				      MESA_multithread_makecurrent_bit)) {
+	 if (gc->thread_id != _glthread_GetID()) {
+	    __glXGenerateError(dpy, gc, gc->xid,
+			       BadAccess, X_GLXMakeContextCurrent);
+	    return False;
+	 }
+      } else {
+	 if (gc->currentDrawable != draw || gc->currentReadable != read ||
+	     dpy != oldGC->currentDpy) {
+	    __glXGenerateError(dpy, gc, gc->xid,
+			       BadAccess, X_GLXMakeContextCurrent);
+	    return False;
+	 }
+	 need_bindcontext = False;
+      }
    }
 
+   if (!need_bindcontext) {
+      bindReturnValue = True;
+   } else
 #ifdef GLX_DIRECT_RENDERING
    /* Bind the direct rendering context to the drawable */
-   if (gc && gc->driContext) {
+   if (need_bindcontext && gc && gc->driContext) {
       __GLXDRIdrawable *pdraw = FetchDRIDrawable(dpy, draw, gc);
       __GLXDRIdrawable *pread = FetchDRIDrawable(dpy, read, gc);
 
@@ -393,7 +410,6 @@ MakeContextCurrent(Display * dpy, GLXDrawable draw,
                                 &reply);
    }
 
-
    if (!bindReturnValue) {
       return False;
    }
@@ -437,6 +453,9 @@ MakeContextCurrent(Display * dpy, GLXDrawable draw,
    else {
       if (oldGC != &dummyContext) {
          /* Old current context is no longer current to anybody */
+	 /* XXX: Except in the presence of MESA_multithread_makecurrent.
+	  * Hmm.
+	  */
          oldGC->currentDpy = 0;
          oldGC->currentDrawable = None;
          oldGC->currentReadable = None;
diff --git a/src/glx/x11/glxextensions.c b/src/glx/x11/glxextensions.c
index 6852128..8ca5417 100644
--- a/src/glx/x11/glxextensions.c
+++ b/src/glx/x11/glxextensions.c
@@ -104,6 +104,7 @@ static const struct extension_info known_glx_extensions[] = {
    { GLX(SGIX_swap_group),             VER(0,0), N, N, N, N },
    { GLX(SGIX_visual_select_group),    VER(0,0), Y, Y, N, N },
    { GLX(EXT_texture_from_pixmap),     VER(0,0), Y, N, N, N },
+   { GLX(MESA_multithread_makecurrent),VER(0,0), Y, N, Y, N },
    { NULL }
 };
 
diff --git a/src/glx/x11/glxextensions.h b/src/glx/x11/glxextensions.h
index 652c5db..9fb4a77 100644
--- a/src/glx/x11/glxextensions.h
+++ b/src/glx/x11/glxextensions.h
@@ -65,7 +65,8 @@ enum
    SGIX_swap_barrier_bit,
    SGIX_swap_group_bit,
    SGIX_visual_select_group_bit,
-   EXT_texture_from_pixmap_bit
+   EXT_texture_from_pixmap_bit,
+   MESA_multithread_makecurrent_bit,
 };
 
 enum
-- 
1.6.4.3

