| /* |
| * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) |
| * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice including the dates of first publication and |
| * either this permission notice or a reference to |
| * http://oss.sgi.com/projects/FreeB/ |
| * shall be included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF |
| * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| * Except as contained in this notice, the name of Silicon Graphics, Inc. |
| * shall not be used in advertising or otherwise to promote the sale, use or |
| * other dealings in this Software without prior written authorization from |
| * Silicon Graphics, Inc. |
| */ |
| |
| /** |
| * \file glxcurrent.c |
| * Client-side GLX interface for current context management. |
| */ |
| |
| #include "glxclient.h" |
| #include "glapi.h" |
| #include "glheader.h" |
| #include "indirect_init.h" |
| |
| #ifdef GLX_DIRECT_RENDERING |
| #include "xf86dri.h" |
| #endif |
| |
| /* |
| ** We setup some dummy structures here so that the API can be used |
| ** even if no context is current. |
| */ |
| |
| static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE]; |
| |
| /* |
| ** Dummy context used by small commands when there is no current context. |
| ** All the |
| ** gl and glx entry points are designed to operate as nop's when using |
| ** the dummy context structure. |
| */ |
| static __GLXcontext dummyContext = { |
| &dummyBuffer[0], |
| &dummyBuffer[0], |
| &dummyBuffer[0], |
| &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE], |
| sizeof(dummyBuffer), |
| }; |
| |
| |
| /* |
| ** All indirect rendering contexts will share the same indirect dispatch table. |
| */ |
| static __GLapi *IndirectAPI = NULL; |
| |
| |
| /* |
| * Current context management and locking |
| */ |
| |
| #if defined( USE_XTHREADS ) |
| |
| /* thread safe */ |
| static GLboolean TSDinitialized = GL_FALSE; |
| static xthread_key_t ContextTSD; |
| |
| _X_HIDDEN __GLXcontext *__glXGetCurrentContext(void) |
| { |
| if (!TSDinitialized) { |
| xthread_key_create(&ContextTSD, NULL); |
| TSDinitialized = GL_TRUE; |
| return &dummyContext; |
| } |
| else { |
| void *p; |
| xthread_get_specific(ContextTSD, &p); |
| if (!p) |
| return &dummyContext; |
| else |
| return (__GLXcontext *) p; |
| } |
| } |
| |
| _X_HIDDEN void __glXSetCurrentContext(__GLXcontext *c) |
| { |
| if (!TSDinitialized) { |
| xthread_key_create(&ContextTSD, NULL); |
| TSDinitialized = GL_TRUE; |
| } |
| xthread_set_specific(ContextTSD, c); |
| } |
| |
| |
| /* Used by the __glXLock() and __glXUnlock() macros */ |
| _X_HIDDEN xmutex_rec __glXmutex; |
| |
| #elif defined( PTHREADS ) |
| |
| _X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; |
| |
| # if defined( GLX_USE_TLS ) |
| |
| /** |
| * Per-thread GLX context pointer. |
| * |
| * \c __glXSetCurrentContext is written is such a way that this pointer can |
| * \b never be \c NULL. This is important! Because of this |
| * \c __glXGetCurrentContext can be implemented as trivial macro. |
| */ |
| __thread void * __glX_tls_Context __attribute__((tls_model("initial-exec"))) |
| = &dummyContext; |
| |
| _X_HIDDEN void __glXSetCurrentContext( __GLXcontext * c ) |
| { |
| __glX_tls_Context = (c != NULL) ? c : &dummyContext; |
| } |
| |
| # else |
| |
| static pthread_once_t once_control = PTHREAD_ONCE_INIT; |
| |
| /** |
| * Per-thread data key. |
| * |
| * Once \c init_thread_data has been called, the per-thread data key will |
| * take a value of \c NULL. As each new thread is created the default |
| * value, in that thread, will be \c NULL. |
| */ |
| static pthread_key_t ContextTSD; |
| |
| /** |
| * Initialize the per-thread data key. |
| * |
| * This function is called \b exactly once per-process (not per-thread!) to |
| * initialize the per-thread data key. This is ideally done using the |
| * \c pthread_once mechanism. |
| */ |
| static void init_thread_data( void ) |
| { |
| if ( pthread_key_create( & ContextTSD, NULL ) != 0 ) { |
| perror( "pthread_key_create" ); |
| exit( -1 ); |
| } |
| } |
| |
| _X_HIDDEN void __glXSetCurrentContext( __GLXcontext * c ) |
| { |
| pthread_once( & once_control, init_thread_data ); |
| pthread_setspecific( ContextTSD, c ); |
| } |
| |
| _X_HIDDEN __GLXcontext * __glXGetCurrentContext( void ) |
| { |
| void * v; |
| |
| pthread_once( & once_control, init_thread_data ); |
| |
| v = pthread_getspecific( ContextTSD ); |
| return (v == NULL) ? & dummyContext : (__GLXcontext *) v; |
| } |
| |
| # endif /* defined( GLX_USE_TLS ) */ |
| |
| #elif defined( THREADS ) |
| |
| #error Unknown threading method specified. |
| |
| #else |
| |
| /* not thread safe */ |
| _X_HIDDEN __GLXcontext *__glXcurrentContext = &dummyContext; |
| |
| #endif |
| |
| |
| _X_HIDDEN void __glXSetCurrentContextNull(void) |
| { |
| __glXSetCurrentContext(&dummyContext); |
| #ifdef GLX_DIRECT_RENDERING |
| _glapi_set_dispatch(NULL); /* no-op functions */ |
| #endif |
| } |
| |
| |
| /************************************************************************/ |
| |
| PUBLIC GLXContext glXGetCurrentContext(void) |
| { |
| GLXContext cx = __glXGetCurrentContext(); |
| |
| if (cx == &dummyContext) { |
| return NULL; |
| } else { |
| return cx; |
| } |
| } |
| |
| PUBLIC GLXDrawable glXGetCurrentDrawable(void) |
| { |
| GLXContext gc = __glXGetCurrentContext(); |
| return gc->currentDrawable; |
| } |
| |
| |
| /************************************************************************/ |
| |
| /** |
| * Sends a GLX protocol message to the specified display to make the context |
| * and the drawables current. |
| * |
| * \param dpy Display to send the message to. |
| * \param opcode Major opcode value for the display. |
| * \param gc_id Context tag for the context to be made current. |
| * \param draw Drawable ID for the "draw" drawable. |
| * \param read Drawable ID for the "read" drawable. |
| * \param reply Space to store the X-server's reply. |
| * |
| * \warning |
| * This function assumes that \c dpy is locked with \c LockDisplay on entry. |
| */ |
| static Bool SendMakeCurrentRequest(Display *dpy, CARD8 opcode, |
| GLXContextID gc_id, GLXContextTag gc_tag, |
| GLXDrawable draw, GLXDrawable read, |
| xGLXMakeCurrentReply *reply) |
| { |
| Bool ret; |
| |
| |
| LockDisplay(dpy); |
| |
| if (draw == read) { |
| xGLXMakeCurrentReq *req; |
| |
| GetReq(GLXMakeCurrent,req); |
| req->reqType = opcode; |
| req->glxCode = X_GLXMakeCurrent; |
| req->drawable = draw; |
| req->context = gc_id; |
| req->oldContextTag = gc_tag; |
| } |
| else { |
| __GLXdisplayPrivate *priv = __glXInitialize(dpy); |
| |
| /* If the server can support the GLX 1.3 version, we should |
| * perfer that. Not only that, some servers support GLX 1.3 but |
| * not the SGI extension. |
| */ |
| |
| if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { |
| xGLXMakeContextCurrentReq *req; |
| |
| GetReq(GLXMakeContextCurrent,req); |
| req->reqType = opcode; |
| req->glxCode = X_GLXMakeContextCurrent; |
| req->drawable = draw; |
| req->readdrawable = read; |
| req->context = gc_id; |
| req->oldContextTag = gc_tag; |
| } |
| else { |
| xGLXVendorPrivateWithReplyReq *vpreq; |
| xGLXMakeCurrentReadSGIReq *req; |
| |
| GetReqExtra(GLXVendorPrivateWithReply, |
| sz_xGLXMakeCurrentReadSGIReq-sz_xGLXVendorPrivateWithReplyReq,vpreq); |
| req = (xGLXMakeCurrentReadSGIReq *)vpreq; |
| req->reqType = opcode; |
| req->glxCode = X_GLXVendorPrivateWithReply; |
| req->vendorCode = X_GLXvop_MakeCurrentReadSGI; |
| req->drawable = draw; |
| req->readable = read; |
| req->context = gc_id; |
| req->oldContextTag = gc_tag; |
| } |
| } |
| |
| ret = _XReply(dpy, (xReply*) reply, 0, False); |
| |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| |
| return ret; |
| } |
| |
| |
| #ifdef GLX_DIRECT_RENDERING |
| static __GLXDRIdrawable * |
| FetchDRIDrawable(Display *dpy, |
| GLXDrawable glxDrawable, GLXContext gc, Bool pre13) |
| { |
| __GLXdisplayPrivate * const priv = __glXInitialize(dpy); |
| __GLXDRIdrawable *pdraw; |
| __GLXscreenConfigs *psc; |
| XID drawable; |
| |
| if (priv == NULL) |
| return NULL; |
| |
| psc = &priv->screenConfigs[gc->screen]; |
| if (psc->drawHash == NULL) |
| return NULL; |
| |
| if (__glxHashLookup(psc->drawHash, glxDrawable, (void *) &pdraw) == 0) |
| return pdraw; |
| |
| /* If this is glXMakeCurrent (pre GLX 1.3) we allow creating the |
| * GLX drawable on the fly. Otherwise we pass None as the X |
| * drawable */ |
| if (pre13) |
| drawable = glxDrawable; |
| else |
| drawable = None; |
| |
| pdraw = psc->driScreen->createDrawable(psc, drawable, |
| glxDrawable, gc->mode); |
| if (__glxHashInsert(psc->drawHash, glxDrawable, pdraw)) { |
| (*pdraw->destroyDrawable)(pdraw); |
| return NULL; |
| } |
| |
| return pdraw; |
| } |
| #endif /* GLX_DIRECT_RENDERING */ |
| |
| |
| /** |
| * Make a particular context current. |
| * |
| * \note This is in this file so that it can access dummyContext. |
| */ |
| static Bool MakeContextCurrent(Display *dpy, GLXDrawable draw, |
| GLXDrawable read, GLXContext gc, |
| Bool pre13) |
| { |
| xGLXMakeCurrentReply reply; |
| const GLXContext oldGC = __glXGetCurrentContext(); |
| const CARD8 opcode = __glXSetupForCommand(dpy); |
| const CARD8 oldOpcode = ((gc == oldGC) || (oldGC == &dummyContext)) |
| ? opcode : __glXSetupForCommand(oldGC->currentDpy); |
| Bool bindReturnValue; |
| |
| |
| if (!opcode || !oldOpcode) { |
| return GL_FALSE; |
| } |
| |
| /* 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. |
| */ |
| if ((gc != NULL) && (gc->xid == None)) { |
| return GL_FALSE; |
| } |
| |
| _glapi_check_multithread(); |
| |
| #ifdef GLX_DIRECT_RENDERING |
| /* Bind the direct rendering context to the drawable */ |
| if (gc && gc->driContext) { |
| __GLXDRIdrawable *pdraw = FetchDRIDrawable(dpy, draw, gc, pre13); |
| __GLXDRIdrawable *pread = FetchDRIDrawable(dpy, read, gc, pre13); |
| |
| bindReturnValue = |
| (gc->driContext->bindContext) (gc->driContext, pdraw, pread); |
| } else |
| #endif |
| { |
| /* Send a glXMakeCurrent request to bind the new context. */ |
| bindReturnValue = |
| SendMakeCurrentRequest(dpy, opcode, gc ? gc->xid : None, |
| ((dpy != oldGC->currentDpy) || oldGC->isDirect) |
| ? None : oldGC->currentContextTag, |
| draw, read, &reply); |
| } |
| |
| |
| if (!bindReturnValue) { |
| return False; |
| } |
| |
| #ifdef GLX_DIRECT_RENDERING |
| if ((dpy != oldGC->currentDpy || (gc && gc->driContext)) && |
| !oldGC->isDirect && oldGC != &dummyContext) { |
| #else |
| if ((dpy != oldGC->currentDpy) && oldGC != &dummyContext) { |
| #endif |
| xGLXMakeCurrentReply dummy_reply; |
| |
| /* We are either switching from one dpy to another and have to |
| * send a request to the previous dpy to unbind the previous |
| * context, or we are switching away from a indirect context to |
| * a direct context and have to send a request to the dpy to |
| * unbind the previous context. |
| */ |
| (void) SendMakeCurrentRequest(oldGC->currentDpy, oldOpcode, None, |
| oldGC->currentContextTag, None, None, |
| & dummy_reply); |
| } |
| #ifdef GLX_DIRECT_RENDERING |
| else if (oldGC->driContext) { |
| oldGC->driContext->unbindContext(oldGC->driContext); |
| } |
| #endif |
| |
| |
| /* Update our notion of what is current */ |
| __glXLock(); |
| if (gc == oldGC) { |
| /* Even though the contexts are the same the drawable might have |
| * changed. Note that gc cannot be the dummy, and that oldGC |
| * cannot be NULL, therefore if they are the same, gc is not |
| * NULL and not the dummy. |
| */ |
| gc->currentDrawable = draw; |
| gc->currentReadable = read; |
| } else { |
| if (oldGC != &dummyContext) { |
| /* Old current context is no longer current to anybody */ |
| oldGC->currentDpy = 0; |
| oldGC->currentDrawable = None; |
| oldGC->currentReadable = None; |
| oldGC->currentContextTag = 0; |
| |
| if (oldGC->xid == None) { |
| /* We are switching away from a context that was |
| * previously destroyed, so we need to free the memory |
| * for the old handle. |
| */ |
| #ifdef GLX_DIRECT_RENDERING |
| /* Destroy the old direct rendering context */ |
| if (oldGC->driContext) { |
| oldGC->driContext->destroyContext(oldGC->driContext, |
| oldGC->psc, |
| oldGC->createDpy); |
| oldGC->driContext = NULL; |
| } |
| #endif |
| __glXFreeContext(oldGC); |
| } |
| } |
| if (gc) { |
| __glXSetCurrentContext(gc); |
| |
| gc->currentDpy = dpy; |
| gc->currentDrawable = draw; |
| gc->currentReadable = read; |
| |
| #ifdef GLX_DIRECT_RENDERING |
| if (!gc->driContext) { |
| #endif |
| if (!IndirectAPI) |
| IndirectAPI = __glXNewIndirectAPI(); |
| _glapi_set_dispatch(IndirectAPI); |
| |
| #ifdef GLX_USE_APPLEGL |
| do { |
| extern void XAppleDRIUseIndirectDispatch(void); |
| XAppleDRIUseIndirectDispatch(); |
| } while (0); |
| #endif |
| |
| __GLXattribute *state = |
| (__GLXattribute *)(gc->client_state_private); |
| |
| gc->currentContextTag = reply.contextTag; |
| if (state->array_state == NULL) { |
| (void) glGetString(GL_EXTENSIONS); |
| (void) glGetString(GL_VERSION); |
| __glXInitVertexArrayState(gc); |
| } |
| #ifdef GLX_DIRECT_RENDERING |
| } |
| else { |
| gc->currentContextTag = -1; |
| } |
| #endif |
| } else { |
| __glXSetCurrentContextNull(); |
| } |
| } |
| __glXUnlock(); |
| return GL_TRUE; |
| } |
| |
| |
| PUBLIC Bool glXMakeCurrent(Display *dpy, GLXDrawable draw, GLXContext gc) |
| { |
| return MakeContextCurrent(dpy, draw, draw, gc, True); |
| } |
| |
| PUBLIC GLX_ALIAS(Bool, glXMakeCurrentReadSGI, |
| (Display *dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx), |
| (dpy, d, r, ctx, False), MakeContextCurrent) |
| |
| PUBLIC GLX_ALIAS(Bool, glXMakeContextCurrent, |
| (Display *dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx), |
| (dpy, d, r, ctx, False), MakeContextCurrent) |