glxcurrent.c revision 3843bbcb4ca4de232dbae6ba3ae619ddfc93508b
1/* 2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) 3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice including the dates of first publication and 13 * either this permission notice or a reference to 14 * http://oss.sgi.com/projects/FreeB/ 15 * shall be included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Except as contained in this notice, the name of Silicon Graphics, Inc. 26 * shall not be used in advertising or otherwise to promote the sale, use or 27 * other dealings in this Software without prior written authorization from 28 * Silicon Graphics, Inc. 29 */ 30 31/** 32 * \file glxcurrent.c 33 * Client-side GLX interface for current context management. 34 */ 35 36#ifdef PTHREADS 37#include <pthread.h> 38#endif 39 40#include "glxclient.h" 41#ifdef GLX_USE_APPLEGL 42#include <stdlib.h> 43 44#include "apple_glx.h" 45#include "apple_glx_context.h" 46#else 47#include "glapi.h" 48#endif 49 50/* 51** We setup some dummy structures here so that the API can be used 52** even if no context is current. 53*/ 54 55static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE]; 56static struct glx_context_vtable dummyVtable; 57/* 58** Dummy context used by small commands when there is no current context. 59** All the 60** gl and glx entry points are designed to operate as nop's when using 61** the dummy context structure. 62*/ 63struct glx_context dummyContext = { 64 &dummyBuffer[0], 65 &dummyBuffer[0], 66 &dummyBuffer[0], 67 &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE], 68 sizeof(dummyBuffer), 69 &dummyVtable 70}; 71 72/* 73 * Current context management and locking 74 */ 75 76#if defined( PTHREADS ) 77 78_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; 79 80# if defined( GLX_USE_TLS ) 81 82/** 83 * Per-thread GLX context pointer. 84 * 85 * \c __glXSetCurrentContext is written is such a way that this pointer can 86 * \b never be \c NULL. This is important! Because of this 87 * \c __glXGetCurrentContext can be implemented as trivial macro. 88 */ 89__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec"))) 90 = &dummyContext; 91 92_X_HIDDEN void 93__glXSetCurrentContext(struct glx_context * c) 94{ 95 __glX_tls_Context = (c != NULL) ? c : &dummyContext; 96} 97 98# else 99 100static pthread_once_t once_control = PTHREAD_ONCE_INIT; 101 102/** 103 * Per-thread data key. 104 * 105 * Once \c init_thread_data has been called, the per-thread data key will 106 * take a value of \c NULL. As each new thread is created the default 107 * value, in that thread, will be \c NULL. 108 */ 109static pthread_key_t ContextTSD; 110 111/** 112 * Initialize the per-thread data key. 113 * 114 * This function is called \b exactly once per-process (not per-thread!) to 115 * initialize the per-thread data key. This is ideally done using the 116 * \c pthread_once mechanism. 117 */ 118static void 119init_thread_data(void) 120{ 121 if (pthread_key_create(&ContextTSD, NULL) != 0) { 122 perror("pthread_key_create"); 123 exit(-1); 124 } 125} 126 127_X_HIDDEN void 128__glXSetCurrentContext(struct glx_context * c) 129{ 130 pthread_once(&once_control, init_thread_data); 131 pthread_setspecific(ContextTSD, c); 132} 133 134_X_HIDDEN struct glx_context * 135__glXGetCurrentContext(void) 136{ 137 void *v; 138 139 pthread_once(&once_control, init_thread_data); 140 141 v = pthread_getspecific(ContextTSD); 142 return (v == NULL) ? &dummyContext : (struct glx_context *) v; 143} 144 145# endif /* defined( GLX_USE_TLS ) */ 146 147#elif defined( THREADS ) 148 149#error Unknown threading method specified. 150 151#else 152 153/* not thread safe */ 154_X_HIDDEN struct glx_context *__glXcurrentContext = &dummyContext; 155 156#endif 157 158 159_X_HIDDEN void 160__glXSetCurrentContextNull(void) 161{ 162 __glXSetCurrentContext(&dummyContext); 163#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 164 _glapi_set_dispatch(NULL); /* no-op functions */ 165 _glapi_set_context(NULL); 166#endif 167} 168 169_X_EXPORT GLXContext 170glXGetCurrentContext(void) 171{ 172 struct glx_context *cx = __glXGetCurrentContext(); 173 174 if (cx == &dummyContext) { 175 return NULL; 176 } 177 else { 178 return (GLXContext) cx; 179 } 180} 181 182_X_EXPORT GLXDrawable 183glXGetCurrentDrawable(void) 184{ 185 struct glx_context *gc = __glXGetCurrentContext(); 186 return gc->currentDrawable; 187} 188 189static void 190__glXGenerateError(Display * dpy, XID resource, 191 BYTE errorCode, CARD16 minorCode) 192{ 193 xError error; 194 195 error.errorCode = errorCode; 196 error.resourceID = resource; 197 error.sequenceNumber = dpy->request; 198 error.type = X_Error; 199 error.majorCode = __glXSetupForCommand(dpy); 200 error.minorCode = minorCode; 201 _XError(dpy, &error); 202} 203 204/** 205 * Make a particular context current. 206 * 207 * \note This is in this file so that it can access dummyContext. 208 */ 209static Bool 210MakeContextCurrent(Display * dpy, GLXDrawable draw, 211 GLXDrawable read, GLXContext gc_user) 212{ 213 struct glx_context *gc = (struct glx_context *) gc_user; 214 struct glx_context *oldGC = __glXGetCurrentContext(); 215 int ret = Success; 216 217#ifndef GLX_USE_APPLEGL 218 /* XXX: If this is left out, then libGL ends up not having this 219 * symbol, and drivers using it fail to load. Compare the 220 * implementation of this symbol to _glapi_noop_enable_warnings(), 221 * though, which gets into the library despite no callers, the same 222 * prototypes, and the same compile flags to the files containing 223 * them. Moving the definition to glapi_nop.c gets it into the 224 * library, though. 225 */ 226 (void)_glthread_GetID(); 227#endif 228 229 /* Make sure that the new context has a nonzero ID. In the request, 230 * a zero context ID is used only to mean that we bind to no current 231 * context. 232 */ 233 if ((gc != NULL) && (gc->xid == None)) { 234 return GL_FALSE; 235 } 236 237 if (gc == NULL && (draw != None || read != None)) { 238 __glXGenerateError(dpy, (draw != None) ? draw : read, 239 BadMatch, X_GLXMakeContextCurrent); 240 return False; 241 } 242 if (gc != NULL && (draw == None || read == None)) { 243 __glXGenerateError(dpy, None, BadMatch, X_GLXMakeContextCurrent); 244 return False; 245 } 246 247#ifndef GLX_USE_APPLEGL 248 _glapi_check_multithread(); 249#endif 250 251 __glXLock(); 252 if (oldGC == gc && 253 gc->currentDrawable == draw && gc->currentReadable == read) { 254 __glXUnlock(); 255 return True; 256 } 257 258 if (oldGC != &dummyContext) { 259 if (--oldGC->thread_refcount == 0) { 260 oldGC->vtable->unbind(oldGC, gc); 261 oldGC->currentDpy = 0; 262 oldGC->currentDrawable = None; 263 oldGC->currentReadable = None; 264 265 if (oldGC->xid == None && oldGC != gc) { 266 /* We are switching away from a context that was 267 * previously destroyed, so we need to free the memory 268 * for the old handle. */ 269 oldGC->vtable->destroy(oldGC); 270 } 271 } 272 } 273 274 if (gc) { 275 if (gc->thread_refcount++ == 0) { 276 gc->currentDpy = dpy; 277 gc->currentDrawable = draw; 278 gc->currentReadable = read; 279 } 280 __glXSetCurrentContext(gc); 281 ret = gc->vtable->bind(gc, oldGC, draw, read); 282 } else { 283 __glXSetCurrentContextNull(); 284 } 285 286 __glXUnlock(); 287 288 if (ret) { 289 __glXGenerateError(dpy, None, ret, X_GLXMakeContextCurrent); 290 return GL_FALSE; 291 } 292 293 return GL_TRUE; 294} 295 296 297_X_EXPORT Bool 298glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc) 299{ 300 return MakeContextCurrent(dpy, draw, draw, gc); 301} 302 303_X_EXPORT 304GLX_ALIAS(Bool, glXMakeCurrentReadSGI, 305 (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx), 306 (dpy, d, r, ctx), MakeContextCurrent) 307 308_X_EXPORT 309GLX_ALIAS(Bool, glXMakeContextCurrent, 310 (Display * dpy, GLXDrawable d, GLXDrawable r, 311 GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent) 312