glxcurrent.c revision 3464ebd5
1cdc920a0Smrg/* 2cdc920a0Smrg * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) 3cdc920a0Smrg * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. 4cdc920a0Smrg * 5cdc920a0Smrg * Permission is hereby granted, free of charge, to any person obtaining a 6cdc920a0Smrg * copy of this software and associated documentation files (the "Software"), 7cdc920a0Smrg * to deal in the Software without restriction, including without limitation 8cdc920a0Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9cdc920a0Smrg * and/or sell copies of the Software, and to permit persons to whom the 10cdc920a0Smrg * Software is furnished to do so, subject to the following conditions: 11cdc920a0Smrg * 12cdc920a0Smrg * The above copyright notice including the dates of first publication and 13cdc920a0Smrg * either this permission notice or a reference to 14cdc920a0Smrg * http://oss.sgi.com/projects/FreeB/ 15cdc920a0Smrg * shall be included in all copies or substantial portions of the Software. 16cdc920a0Smrg * 17cdc920a0Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18cdc920a0Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19cdc920a0Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20cdc920a0Smrg * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21cdc920a0Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 22cdc920a0Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23cdc920a0Smrg * SOFTWARE. 24cdc920a0Smrg * 25cdc920a0Smrg * Except as contained in this notice, the name of Silicon Graphics, Inc. 26cdc920a0Smrg * shall not be used in advertising or otherwise to promote the sale, use or 27cdc920a0Smrg * other dealings in this Software without prior written authorization from 28cdc920a0Smrg * Silicon Graphics, Inc. 29cdc920a0Smrg */ 30cdc920a0Smrg 31cdc920a0Smrg/** 32cdc920a0Smrg * \file glxcurrent.c 33cdc920a0Smrg * Client-side GLX interface for current context management. 34cdc920a0Smrg */ 35cdc920a0Smrg 36cdc920a0Smrg#ifdef PTHREADS 37cdc920a0Smrg#include <pthread.h> 38cdc920a0Smrg#endif 39cdc920a0Smrg 40cdc920a0Smrg#include "glxclient.h" 41cdc920a0Smrg#ifdef GLX_USE_APPLEGL 42cdc920a0Smrg#include <stdlib.h> 43cdc920a0Smrg 44cdc920a0Smrg#include "apple_glx.h" 45cdc920a0Smrg#include "apple_glx_context.h" 46cdc920a0Smrg#endif 47cdc920a0Smrg 483464ebd5Sriastradh#include "glapi.h" 493464ebd5Sriastradh 50cdc920a0Smrg/* 51cdc920a0Smrg** We setup some dummy structures here so that the API can be used 52cdc920a0Smrg** even if no context is current. 53cdc920a0Smrg*/ 54cdc920a0Smrg 55cdc920a0Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE]; 563464ebd5Sriastradhstatic struct glx_context_vtable dummyVtable; 57cdc920a0Smrg/* 58cdc920a0Smrg** Dummy context used by small commands when there is no current context. 59cdc920a0Smrg** All the 60cdc920a0Smrg** gl and glx entry points are designed to operate as nop's when using 61cdc920a0Smrg** the dummy context structure. 62cdc920a0Smrg*/ 633464ebd5Sriastradhstruct glx_context dummyContext = { 64cdc920a0Smrg &dummyBuffer[0], 65cdc920a0Smrg &dummyBuffer[0], 66cdc920a0Smrg &dummyBuffer[0], 67cdc920a0Smrg &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE], 68cdc920a0Smrg sizeof(dummyBuffer), 693464ebd5Sriastradh &dummyVtable 70cdc920a0Smrg}; 71cdc920a0Smrg 72cdc920a0Smrg/* 73cdc920a0Smrg * Current context management and locking 74cdc920a0Smrg */ 75cdc920a0Smrg 76cdc920a0Smrg#if defined( PTHREADS ) 77cdc920a0Smrg 78cdc920a0Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; 79cdc920a0Smrg 80cdc920a0Smrg# if defined( GLX_USE_TLS ) 81cdc920a0Smrg 82cdc920a0Smrg/** 83cdc920a0Smrg * Per-thread GLX context pointer. 84cdc920a0Smrg * 85cdc920a0Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can 86cdc920a0Smrg * \b never be \c NULL. This is important! Because of this 87cdc920a0Smrg * \c __glXGetCurrentContext can be implemented as trivial macro. 88cdc920a0Smrg */ 89cdc920a0Smrg__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec"))) 90cdc920a0Smrg = &dummyContext; 91cdc920a0Smrg 92cdc920a0Smrg_X_HIDDEN void 933464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c) 94cdc920a0Smrg{ 95cdc920a0Smrg __glX_tls_Context = (c != NULL) ? c : &dummyContext; 96cdc920a0Smrg} 97cdc920a0Smrg 98cdc920a0Smrg# else 99cdc920a0Smrg 100cdc920a0Smrgstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 101cdc920a0Smrg 102cdc920a0Smrg/** 103cdc920a0Smrg * Per-thread data key. 104cdc920a0Smrg * 105cdc920a0Smrg * Once \c init_thread_data has been called, the per-thread data key will 106cdc920a0Smrg * take a value of \c NULL. As each new thread is created the default 107cdc920a0Smrg * value, in that thread, will be \c NULL. 108cdc920a0Smrg */ 109cdc920a0Smrgstatic pthread_key_t ContextTSD; 110cdc920a0Smrg 111cdc920a0Smrg/** 112cdc920a0Smrg * Initialize the per-thread data key. 113cdc920a0Smrg * 114cdc920a0Smrg * This function is called \b exactly once per-process (not per-thread!) to 115cdc920a0Smrg * initialize the per-thread data key. This is ideally done using the 116cdc920a0Smrg * \c pthread_once mechanism. 117cdc920a0Smrg */ 118cdc920a0Smrgstatic void 119cdc920a0Smrginit_thread_data(void) 120cdc920a0Smrg{ 121cdc920a0Smrg if (pthread_key_create(&ContextTSD, NULL) != 0) { 122cdc920a0Smrg perror("pthread_key_create"); 123cdc920a0Smrg exit(-1); 124cdc920a0Smrg } 125cdc920a0Smrg} 126cdc920a0Smrg 127cdc920a0Smrg_X_HIDDEN void 1283464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c) 129cdc920a0Smrg{ 130cdc920a0Smrg pthread_once(&once_control, init_thread_data); 131cdc920a0Smrg pthread_setspecific(ContextTSD, c); 132cdc920a0Smrg} 133cdc920a0Smrg 1343464ebd5Sriastradh_X_HIDDEN struct glx_context * 135cdc920a0Smrg__glXGetCurrentContext(void) 136cdc920a0Smrg{ 137cdc920a0Smrg void *v; 138cdc920a0Smrg 139cdc920a0Smrg pthread_once(&once_control, init_thread_data); 140cdc920a0Smrg 141cdc920a0Smrg v = pthread_getspecific(ContextTSD); 1423464ebd5Sriastradh return (v == NULL) ? &dummyContext : (struct glx_context *) v; 143cdc920a0Smrg} 144cdc920a0Smrg 145cdc920a0Smrg# endif /* defined( GLX_USE_TLS ) */ 146cdc920a0Smrg 147cdc920a0Smrg#elif defined( THREADS ) 148cdc920a0Smrg 149cdc920a0Smrg#error Unknown threading method specified. 150cdc920a0Smrg 151cdc920a0Smrg#else 152cdc920a0Smrg 153cdc920a0Smrg/* not thread safe */ 1543464ebd5Sriastradh_X_HIDDEN struct glx_context *__glXcurrentContext = &dummyContext; 155cdc920a0Smrg 156cdc920a0Smrg#endif 157cdc920a0Smrg 158cdc920a0Smrg 159cdc920a0Smrg_X_HIDDEN void 160cdc920a0Smrg__glXSetCurrentContextNull(void) 161cdc920a0Smrg{ 162cdc920a0Smrg __glXSetCurrentContext(&dummyContext); 1633464ebd5Sriastradh#if defined(GLX_DIRECT_RENDERING) 164cdc920a0Smrg _glapi_set_dispatch(NULL); /* no-op functions */ 165cdc920a0Smrg _glapi_set_context(NULL); 166cdc920a0Smrg#endif 167cdc920a0Smrg} 168cdc920a0Smrg 1693464ebd5Sriastradh_X_EXPORT GLXContext 170cdc920a0SmrgglXGetCurrentContext(void) 171cdc920a0Smrg{ 1723464ebd5Sriastradh struct glx_context *cx = __glXGetCurrentContext(); 173cdc920a0Smrg 174cdc920a0Smrg if (cx == &dummyContext) { 175cdc920a0Smrg return NULL; 176cdc920a0Smrg } 177cdc920a0Smrg else { 1783464ebd5Sriastradh return (GLXContext) cx; 179cdc920a0Smrg } 180cdc920a0Smrg} 181cdc920a0Smrg 1823464ebd5Sriastradh_X_EXPORT GLXDrawable 183cdc920a0SmrgglXGetCurrentDrawable(void) 184cdc920a0Smrg{ 1853464ebd5Sriastradh struct glx_context *gc = __glXGetCurrentContext(); 186cdc920a0Smrg return gc->currentDrawable; 187cdc920a0Smrg} 188cdc920a0Smrg 189cdc920a0Smrgstatic void 1903464ebd5Sriastradh__glXGenerateError(Display * dpy, XID resource, 191cdc920a0Smrg BYTE errorCode, CARD16 minorCode) 192cdc920a0Smrg{ 193cdc920a0Smrg xError error; 194cdc920a0Smrg 195cdc920a0Smrg error.errorCode = errorCode; 196cdc920a0Smrg error.resourceID = resource; 197cdc920a0Smrg error.sequenceNumber = dpy->request; 198cdc920a0Smrg error.type = X_Error; 1993464ebd5Sriastradh error.majorCode = __glXSetupForCommand(dpy); 200cdc920a0Smrg error.minorCode = minorCode; 201cdc920a0Smrg _XError(dpy, &error); 202cdc920a0Smrg} 203cdc920a0Smrg 204cdc920a0Smrg/** 205cdc920a0Smrg * Make a particular context current. 206cdc920a0Smrg * 207cdc920a0Smrg * \note This is in this file so that it can access dummyContext. 208cdc920a0Smrg */ 209cdc920a0Smrgstatic Bool 210cdc920a0SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw, 2113464ebd5Sriastradh GLXDrawable read, GLXContext gc_user) 212cdc920a0Smrg{ 2133464ebd5Sriastradh struct glx_context *gc = (struct glx_context *) gc_user; 2143464ebd5Sriastradh struct glx_context *oldGC = __glXGetCurrentContext(); 2153464ebd5Sriastradh 2163464ebd5Sriastradh /* XXX: If this is left out, then libGL ends up not having this 2173464ebd5Sriastradh * symbol, and drivers using it fail to load. Compare the 2183464ebd5Sriastradh * implementation of this symbol to _glapi_noop_enable_warnings(), 2193464ebd5Sriastradh * though, which gets into the library despite no callers, the same 2203464ebd5Sriastradh * prototypes, and the same compile flags to the files containing 2213464ebd5Sriastradh * them. Moving the definition to glapi_nop.c gets it into the 2223464ebd5Sriastradh * library, though. 2233464ebd5Sriastradh */ 2243464ebd5Sriastradh (void)_glthread_GetID(); 225cdc920a0Smrg 226cdc920a0Smrg /* Make sure that the new context has a nonzero ID. In the request, 227cdc920a0Smrg * a zero context ID is used only to mean that we bind to no current 228cdc920a0Smrg * context. 229cdc920a0Smrg */ 230cdc920a0Smrg if ((gc != NULL) && (gc->xid == None)) { 231cdc920a0Smrg return GL_FALSE; 232cdc920a0Smrg } 233cdc920a0Smrg 234cdc920a0Smrg if (gc == NULL && (draw != None || read != None)) { 2353464ebd5Sriastradh __glXGenerateError(dpy, (draw != None) ? draw : read, 236cdc920a0Smrg BadMatch, X_GLXMakeContextCurrent); 237cdc920a0Smrg return False; 238cdc920a0Smrg } 239cdc920a0Smrg if (gc != NULL && (draw == None || read == None)) { 2403464ebd5Sriastradh __glXGenerateError(dpy, None, BadMatch, X_GLXMakeContextCurrent); 241cdc920a0Smrg return False; 242cdc920a0Smrg } 243cdc920a0Smrg 244cdc920a0Smrg _glapi_check_multithread(); 245cdc920a0Smrg 2463464ebd5Sriastradh __glXLock(); 2473464ebd5Sriastradh if (oldGC == gc && 2483464ebd5Sriastradh gc->currentDrawable == draw && gc->currentReadable == read) { 2493464ebd5Sriastradh __glXUnlock(); 2503464ebd5Sriastradh return True; 251cdc920a0Smrg } 252cdc920a0Smrg 2533464ebd5Sriastradh if (oldGC != &dummyContext) { 2543464ebd5Sriastradh if (--oldGC->thread_refcount == 0) { 2553464ebd5Sriastradh oldGC->vtable->unbind(oldGC, gc); 2563464ebd5Sriastradh oldGC->currentDpy = 0; 257cdc920a0Smrg } 258cdc920a0Smrg } 259cdc920a0Smrg 2603464ebd5Sriastradh if (gc) { 2613464ebd5Sriastradh /* Attempt to bind the context. We do this before mucking with 2623464ebd5Sriastradh * gc and __glXSetCurrentContext to properly handle our state in 2633464ebd5Sriastradh * case of an error. 2643464ebd5Sriastradh * 2653464ebd5Sriastradh * If an error occurs, set the Null context since we've already 2663464ebd5Sriastradh * blown away our old context. The caller is responsible for 2673464ebd5Sriastradh * figuring out how to handle setting a valid context. 268cdc920a0Smrg */ 2693464ebd5Sriastradh if (gc->vtable->bind(gc, oldGC, draw, read) != Success) { 2703464ebd5Sriastradh __glXSetCurrentContextNull(); 2713464ebd5Sriastradh __glXUnlock(); 2723464ebd5Sriastradh __glXGenerateError(dpy, None, GLXBadContext, X_GLXMakeContextCurrent); 2733464ebd5Sriastradh return GL_FALSE; 274cdc920a0Smrg } 275cdc920a0Smrg 2763464ebd5Sriastradh if (gc->thread_refcount == 0) { 277cdc920a0Smrg gc->currentDpy = dpy; 278cdc920a0Smrg gc->currentDrawable = draw; 279cdc920a0Smrg gc->currentReadable = read; 280cdc920a0Smrg } 2813464ebd5Sriastradh gc->thread_refcount++; 2823464ebd5Sriastradh __glXSetCurrentContext(gc); 2833464ebd5Sriastradh } else { 2843464ebd5Sriastradh __glXSetCurrentContextNull(); 2853464ebd5Sriastradh } 2863464ebd5Sriastradh 2873464ebd5Sriastradh if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) { 2883464ebd5Sriastradh /* We are switching away from a context that was 2893464ebd5Sriastradh * previously destroyed, so we need to free the memory 2903464ebd5Sriastradh * for the old handle. */ 2913464ebd5Sriastradh oldGC->vtable->destroy(oldGC); 292cdc920a0Smrg } 2933464ebd5Sriastradh 294cdc920a0Smrg __glXUnlock(); 2953464ebd5Sriastradh 296cdc920a0Smrg return GL_TRUE; 297cdc920a0Smrg} 298cdc920a0Smrg 299cdc920a0Smrg 3003464ebd5Sriastradh_X_EXPORT Bool 301cdc920a0SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc) 302cdc920a0Smrg{ 303cdc920a0Smrg return MakeContextCurrent(dpy, draw, draw, gc); 304cdc920a0Smrg} 305cdc920a0Smrg 3063464ebd5Sriastradh_X_EXPORT 307cdc920a0SmrgGLX_ALIAS(Bool, glXMakeCurrentReadSGI, 308cdc920a0Smrg (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx), 309cdc920a0Smrg (dpy, d, r, ctx), MakeContextCurrent) 310cdc920a0Smrg 3113464ebd5Sriastradh_X_EXPORT 312cdc920a0SmrgGLX_ALIAS(Bool, glXMakeContextCurrent, 313cdc920a0Smrg (Display * dpy, GLXDrawable d, GLXDrawable r, 314cdc920a0Smrg GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent) 315