| /* |
| * 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 "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( 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) |
| { |
| __GLXdisplayPrivate *const priv = __glXInitialize(dpy); |
| __GLXDRIdrawable *pdraw; |
| __GLXscreenConfigs *psc; |
| |
| 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; |
| |
| pdraw = psc->driScreen->createDrawable(psc, glxDrawable, |
| glxDrawable, gc->mode); |
| if (__glxHashInsert(psc->drawHash, glxDrawable, pdraw)) { |
| (*pdraw->destroyDrawable) (pdraw); |
| return NULL; |
| } |
| |
| return pdraw; |
| } |
| #endif /* GLX_DIRECT_RENDERING */ |
| |
| static void |
| __glXGenerateError(Display * dpy, GLXContext gc, XID resource, |
| BYTE errorCode, CARD16 minorCode) |
| { |
| xError error; |
| |
| error.errorCode = errorCode; |
| error.resourceID = resource; |
| error.sequenceNumber = dpy->request; |
| error.type = X_Error; |
| error.majorCode = gc->majorOpcode; |
| error.minorCode = minorCode; |
| _XError(dpy, &error); |
| } |
| |
| /** |
| * 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) |
| { |
| xGLXMakeCurrentReply reply; |
| const GLXContext oldGC = __glXGetCurrentContext(); |
| const CARD8 opcode = __glXSetupForCommand(dpy); |
| const CARD8 oldOpcode = ((gc == oldGC) || (oldGC == &dummyContext)) |
| ? opcode : __glXSetupForCommand(oldGC->currentDpy); |
| Bool bindReturnValue; |
| __GLXattribute *state; |
| |
| 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; |
| } |
| |
| if (gc == NULL && (draw != None || read != None)) { |
| __glXGenerateError(dpy, gc, (draw != None) ? draw : read, |
| BadMatch, X_GLXMakeContextCurrent); |
| return False; |
| } |
| if (gc != NULL && (draw == None || read == None)) { |
| __glXGenerateError(dpy, gc, None, BadMatch, X_GLXMakeContextCurrent); |
| return False; |
| } |
| |
| _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; |
| } |
| |
| #ifdef GLX_DIRECT_RENDERING |
| /* Bind the direct rendering context to the drawable */ |
| if (gc && gc->driContext) { |
| __GLXDRIdrawable *pdraw = FetchDRIDrawable(dpy, draw, gc); |
| __GLXDRIdrawable *pread = FetchDRIDrawable(dpy, read, gc); |
| |
| if ((pdraw == NULL) || (pread == NULL)) { |
| __glXGenerateError(dpy, gc, (pdraw == NULL) ? draw : read, |
| GLXBadDrawable, X_GLXMakeContextCurrent); |
| return False; |
| } |
| |
| bindReturnValue = |
| (gc->driContext->bindContext) (gc->driContext, pdraw, pread); |
| } |
| else if (!gc && oldGC && oldGC->driContext) { |
| bindReturnValue = True; |
| } |
| 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 != gc) { |
| 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; |
| oldGC->thread_id = 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; |
| gc->thread_id = _glthread_GetID(); |
| |
| #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 |
| |
| 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); |
| } |
| |
| PUBLIC |
| GLX_ALIAS(Bool, glXMakeCurrentReadSGI, |
| (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx), |
| (dpy, d, r, ctx), MakeContextCurrent) |
| |
| PUBLIC |
| GLX_ALIAS(Bool, glXMakeContextCurrent, |
| (Display * dpy, GLXDrawable d, GLXDrawable r, |
| GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent) |