diff options
-rw-r--r-- | docs/MESA_multithread_makecurrent.spec | 135 | ||||
-rw-r--r-- | src/glx/glxclient.h | 4 | ||||
-rw-r--r-- | src/glx/glxcurrent.c | 55 | ||||
-rw-r--r-- | src/glx/glxextensions.c | 1 | ||||
-rw-r--r-- | src/glx/glxextensions.h | 1 |
5 files changed, 172 insertions, 24 deletions
diff --git a/docs/MESA_multithread_makecurrent.spec b/docs/MESA_multithread_makecurrent.spec new file mode 100644 index 00000000000..68ade762436 --- /dev/null +++ b/docs/MESA_multithread_makecurrent.spec @@ -0,0 +1,135 @@ +Name + + MESA_multithread_makecurrent + +Name Strings + + GLX_MESA_multithread_makecurrent + +Contact + + Eric Anholt ([email protected]) + +Status + + Not shipping. + +Version + + Last Modified Date: 21 February 2011 + +Number + + TBD + +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 write access + to 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 mutex is both higher performance and easier to + implement. This extension gives those applications that option by + relaxing the context binding requirements. + + This new behavior matches the requirements of AGL, while providing + a feature not specified in WGL. + +IP Status + + Open-source; freely implementable. + +Issues + + None. + +New Procedures and Functions + + None. + +New Tokens + + None. + +Changes to Chapter 3 of the GLX 1.3 Specification (Functions and Errors) + + Remove the following sentence from section 3.3.7 Rendering Contexts: + If ctx is current to some other thread, then + glXMakeContextCurrent will generate a BadAccess error. + + Remove the following sentence from section 3.5 Rendering Contexts: + If ctx is current to some other thread, then + glXMakeCurrent will generate a BadAccess error. + +GLX Protocol + + None. The GLX extension is client-side. + +Errors + + None. + +New State + + None. + +Issues + + (1) What happens if the app binds a context/drawable in multiple + threads, then binds a different context/thread in one of them? + + As with binding a new context from the current thread, the old + context's refcount is reduced and the new context's refcount is + increased. + + (2) What happens if the app binds a context/drawable in multiple + threads, then binds None/None in one of them? + + The GLX context is unreferenced from that thread, and the other + threads retain their GLX context binding. + + (3) What happens if the app binds a context/drawable in 7 threads, + then destroys the context in one of them? + + As with GLX context destruction previously, the XID is destroyed + but the context remains usable by threads that have the context + current. + + (4) What happens if the app binds a new drawable/readable with + glXMakeCurrent() when it is already bound to another thread? + + The context becomes bound to the new drawable/readable, and + further rendering in either thread will use the new + drawable/readable. + + (5) What requirements should be placed on the user managing contexts + from multiple threads? + + The intention is to allow multithreaded access to the GL at the + minimal performance cost, so requiring that the GL do general + synchronization (beyond that already required by context sharing) + is not an option, and synchronizing of GL's access to the GL + context between multiple threads is left to the application to do + across GL calls. However, it would be unfortunate for a library + doing multithread_makecurrent to require that other libraries + share in synchronization for binding of their own contexts, so the + refcounting of the contexts is required to be threadsafe. + +Revision History + + 20 November 2009 Eric Anholt - initial specification + 22 November 2009 Eric Anholt - added issues from Ian Romanick. + 3 February 2011 Eric Anholt - updated with resolution to issues 1-3 + 3 February 2011 Eric Anholt - added issue 4, 5 + 21 February 2011 Eric Anholt - Include glXMakeCurrent() sentence + along with glXMakeContextCurrent() for removal. diff --git a/src/glx/glxclient.h b/src/glx/glxclient.h index fdcef8075a8..2b6966f2e08 100644 --- a/src/glx/glxclient.h +++ b/src/glx/glxclient.h @@ -419,9 +419,9 @@ struct glx_context /*@} */ /** - * Thread ID we're currently current in. Zero if none. + * Number of threads we're currently current in. */ - unsigned long thread_id; + unsigned long thread_refcount; char gl_extension_bits[__GL_EXT_BYTES]; }; diff --git a/src/glx/glxcurrent.c b/src/glx/glxcurrent.c index 36317383544..9a6499037b1 100644 --- a/src/glx/glxcurrent.c +++ b/src/glx/glxcurrent.c @@ -216,6 +216,16 @@ MakeContextCurrent(Display * dpy, GLXDrawable draw, struct glx_context *oldGC = __glXGetCurrentContext(); int ret = Success; + /* XXX: If this is left out, then libGL ends up not having this + * symbol, and drivers using it fail to load. Compare the + * implementation of this symbol to _glapi_noop_enable_warnings(), + * though, which gets into the library despite no callers, the same + * prototypes, and the same compile flags to the files containing + * them. Moving the definition to glapi_nop.c gets it into the + * library, though. + */ + (void)_glthread_GetID(); + /* Make sure that the new context has a nonzero ID. In the request, * a zero context ID is used only to mean that we bind to no current * context. @@ -236,41 +246,42 @@ 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; - } - + __glXLock(); if (oldGC == gc && - gc->currentDrawable == draw && gc->currentReadable == read) + gc->currentDrawable == draw && gc->currentReadable == read) { + __glXUnlock(); return True; + } if (oldGC != &dummyContext) { - oldGC->vtable->unbind(oldGC, gc); - oldGC->currentDpy = 0; - oldGC->currentDrawable = None; - oldGC->currentReadable = None; - oldGC->thread_id = 0; + if (--oldGC->thread_refcount == 0) { + oldGC->vtable->unbind(oldGC, gc); + oldGC->currentDpy = 0; + oldGC->currentDrawable = None; + oldGC->currentReadable = None; + + if (oldGC->xid == None && oldGC != gc) { + /* We are switching away from a context that was + * previously destroyed, so we need to free the memory + * for the old handle. */ + oldGC->vtable->destroy(oldGC); + } + } } if (gc) { - gc->currentDpy = dpy; - gc->currentDrawable = draw; - gc->currentReadable = read; - gc->thread_id = _glthread_GetID(); + if (gc->thread_refcount++ == 0) { + gc->currentDpy = dpy; + gc->currentDrawable = draw; + gc->currentReadable = read; + } __glXSetCurrentContext(gc); ret = gc->vtable->bind(gc, oldGC, draw, read); } else { __glXSetCurrentContextNull(); } - if (oldGC != &dummyContext && oldGC->xid == None && oldGC != gc) { - /* We are switching away from a context that was - * previously destroyed, so we need to free the memory - * for the old handle. */ - oldGC->vtable->destroy(oldGC); - } + __glXUnlock(); if (ret) { __glXGenerateError(dpy, gc, None, ret, X_GLXMakeContextCurrent); diff --git a/src/glx/glxextensions.c b/src/glx/glxextensions.c index 3a0e64c46d1..ffd466479b4 100644 --- a/src/glx/glxextensions.c +++ b/src/glx/glxextensions.c @@ -90,6 +90,7 @@ static const struct extension_info known_glx_extensions[] = { { GLX(MESA_agp_offset), VER(0,0), N, N, N, Y }, /* Deprecated */ { GLX(MESA_copy_sub_buffer), VER(0,0), Y, N, N, N }, #endif + { GLX(MESA_multithread_makecurrent),VER(0,0), Y, N, Y, N }, { GLX(MESA_pixmap_colormap), VER(0,0), N, N, N, N }, /* Deprecated */ { GLX(MESA_release_buffers), VER(0,0), N, N, N, N }, /* Deprecated */ #ifdef GLX_USE_APPLEGL diff --git a/src/glx/glxextensions.h b/src/glx/glxextensions.h index 78776618338..333b3f9adbd 100644 --- a/src/glx/glxextensions.h +++ b/src/glx/glxextensions.h @@ -43,6 +43,7 @@ enum MESA_agp_offset_bit, MESA_copy_sub_buffer_bit, MESA_depth_float_bit, + MESA_multithread_makecurrent_bit, MESA_pixmap_colormap_bit, MESA_release_buffers_bit, MESA_swap_control_bit, |