glxcurrent.c revision b8e80941
1848b8605Smrg/* 2848b8605Smrg * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) 3848b8605Smrg * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. 4848b8605Smrg * 5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 6848b8605Smrg * copy of this software and associated documentation files (the "Software"), 7848b8605Smrg * to deal in the Software without restriction, including without limitation 8848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 10848b8605Smrg * Software is furnished to do so, subject to the following conditions: 11848b8605Smrg * 12848b8605Smrg * The above copyright notice including the dates of first publication and 13848b8605Smrg * either this permission notice or a reference to 14848b8605Smrg * http://oss.sgi.com/projects/FreeB/ 15848b8605Smrg * shall be included in all copies or substantial portions of the Software. 16848b8605Smrg * 17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20848b8605Smrg * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21848b8605Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 22848b8605Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23848b8605Smrg * SOFTWARE. 24848b8605Smrg * 25848b8605Smrg * Except as contained in this notice, the name of Silicon Graphics, Inc. 26848b8605Smrg * shall not be used in advertising or otherwise to promote the sale, use or 27848b8605Smrg * other dealings in this Software without prior written authorization from 28848b8605Smrg * Silicon Graphics, Inc. 29848b8605Smrg */ 30848b8605Smrg 31848b8605Smrg/** 32848b8605Smrg * \file glxcurrent.c 33848b8605Smrg * Client-side GLX interface for current context management. 34848b8605Smrg */ 35848b8605Smrg 36848b8605Smrg#include <pthread.h> 37848b8605Smrg 38848b8605Smrg#include "glxclient.h" 39848b8605Smrg#include "glapi.h" 40b8e80941Smrg#include "glx_error.h" 41b8e80941Smrg 42b8e80941Smrg/* 43b8e80941Smrg * MASSIVE KLUDGE! 44b8e80941Smrg * We need these to not be extern in libGL.so because of 45b8e80941Smrg * PR toolchain/50277 46b8e80941Smrg */ 47b8e80941Smrg#if defined(GLX_USE_TLS) && defined(__NetBSD__) 48b8e80941Smrg_X_EXPORT __thread struct _glapi_table * _glapi_tls_Dispatch 49b8e80941Smrg __attribute__((tls_model("initial-exec"))) = NULL; 50b8e80941Smrg_X_EXPORT __thread void * _glapi_tls_Context 51b8e80941Smrg __attribute__((tls_model("initial-exec"))); 52b8e80941Smrg#endif 53848b8605Smrg 54848b8605Smrg/* 55848b8605Smrg** We setup some dummy structures here so that the API can be used 56848b8605Smrg** even if no context is current. 57848b8605Smrg*/ 58848b8605Smrg 59848b8605Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE]; 60848b8605Smrgstatic struct glx_context_vtable dummyVtable; 61848b8605Smrg/* 62848b8605Smrg** Dummy context used by small commands when there is no current context. 63848b8605Smrg** All the 64848b8605Smrg** gl and glx entry points are designed to operate as nop's when using 65848b8605Smrg** the dummy context structure. 66848b8605Smrg*/ 67848b8605Smrgstruct glx_context dummyContext = { 68848b8605Smrg &dummyBuffer[0], 69848b8605Smrg &dummyBuffer[0], 70848b8605Smrg &dummyBuffer[0], 71848b8605Smrg &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE], 72848b8605Smrg sizeof(dummyBuffer), 73848b8605Smrg &dummyVtable 74848b8605Smrg}; 75848b8605Smrg 76848b8605Smrg/* 77848b8605Smrg * Current context management and locking 78848b8605Smrg */ 79848b8605Smrg 80848b8605Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; 81848b8605Smrg 82848b8605Smrg# if defined( GLX_USE_TLS ) 83848b8605Smrg 84848b8605Smrg/** 85848b8605Smrg * Per-thread GLX context pointer. 86848b8605Smrg * 87848b8605Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can 88848b8605Smrg * \b never be \c NULL. This is important! Because of this 89848b8605Smrg * \c __glXGetCurrentContext can be implemented as trivial macro. 90848b8605Smrg */ 91848b8605Smrg__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec"))) 92b8e80941Smrg#if defined(__NetBSD__) 93b8e80941Smrg = NULL; /* non-zero initializers not supported with dlopen */ 94b8e80941Smrg#else 95848b8605Smrg = &dummyContext; 96b8e80941Smrg#endif 97848b8605Smrg 98848b8605Smrg_X_HIDDEN void 99848b8605Smrg__glXSetCurrentContext(struct glx_context * c) 100848b8605Smrg{ 101848b8605Smrg __glX_tls_Context = (c != NULL) ? c : &dummyContext; 102848b8605Smrg} 103848b8605Smrg 104848b8605Smrg# else 105848b8605Smrg 106848b8605Smrgstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 107848b8605Smrg 108848b8605Smrg/** 109848b8605Smrg * Per-thread data key. 110848b8605Smrg * 111848b8605Smrg * Once \c init_thread_data has been called, the per-thread data key will 112848b8605Smrg * take a value of \c NULL. As each new thread is created the default 113848b8605Smrg * value, in that thread, will be \c NULL. 114848b8605Smrg */ 115848b8605Smrgstatic pthread_key_t ContextTSD; 116848b8605Smrg 117848b8605Smrg/** 118848b8605Smrg * Initialize the per-thread data key. 119848b8605Smrg * 120848b8605Smrg * This function is called \b exactly once per-process (not per-thread!) to 121848b8605Smrg * initialize the per-thread data key. This is ideally done using the 122848b8605Smrg * \c pthread_once mechanism. 123848b8605Smrg */ 124848b8605Smrgstatic void 125848b8605Smrginit_thread_data(void) 126848b8605Smrg{ 127848b8605Smrg if (pthread_key_create(&ContextTSD, NULL) != 0) { 128848b8605Smrg perror("pthread_key_create"); 129848b8605Smrg exit(-1); 130848b8605Smrg } 131848b8605Smrg} 132848b8605Smrg 133848b8605Smrg_X_HIDDEN void 134848b8605Smrg__glXSetCurrentContext(struct glx_context * c) 135848b8605Smrg{ 136848b8605Smrg pthread_once(&once_control, init_thread_data); 137848b8605Smrg pthread_setspecific(ContextTSD, c); 138848b8605Smrg} 139848b8605Smrg 140848b8605Smrg_X_HIDDEN struct glx_context * 141848b8605Smrg__glXGetCurrentContext(void) 142848b8605Smrg{ 143848b8605Smrg void *v; 144848b8605Smrg 145848b8605Smrg pthread_once(&once_control, init_thread_data); 146848b8605Smrg 147848b8605Smrg v = pthread_getspecific(ContextTSD); 148848b8605Smrg return (v == NULL) ? &dummyContext : (struct glx_context *) v; 149848b8605Smrg} 150848b8605Smrg 151848b8605Smrg# endif /* defined( GLX_USE_TLS ) */ 152848b8605Smrg 153848b8605Smrg 154848b8605Smrg_X_HIDDEN void 155848b8605Smrg__glXSetCurrentContextNull(void) 156848b8605Smrg{ 157848b8605Smrg __glXSetCurrentContext(&dummyContext); 158848b8605Smrg#if defined(GLX_DIRECT_RENDERING) 159848b8605Smrg _glapi_set_dispatch(NULL); /* no-op functions */ 160848b8605Smrg _glapi_set_context(NULL); 161848b8605Smrg#endif 162848b8605Smrg} 163848b8605Smrg 164b8e80941Smrg_GLX_PUBLIC GLXContext 165848b8605SmrgglXGetCurrentContext(void) 166848b8605Smrg{ 167848b8605Smrg struct glx_context *cx = __glXGetCurrentContext(); 168848b8605Smrg 169848b8605Smrg if (cx == &dummyContext) { 170848b8605Smrg return NULL; 171848b8605Smrg } 172848b8605Smrg else { 173848b8605Smrg return (GLXContext) cx; 174848b8605Smrg } 175848b8605Smrg} 176848b8605Smrg 177b8e80941Smrg_GLX_PUBLIC GLXDrawable 178848b8605SmrgglXGetCurrentDrawable(void) 179848b8605Smrg{ 180848b8605Smrg struct glx_context *gc = __glXGetCurrentContext(); 181848b8605Smrg return gc->currentDrawable; 182848b8605Smrg} 183848b8605Smrg 184848b8605Smrg/** 185848b8605Smrg * Make a particular context current. 186848b8605Smrg * 187848b8605Smrg * \note This is in this file so that it can access dummyContext. 188848b8605Smrg */ 189848b8605Smrgstatic Bool 190848b8605SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw, 191848b8605Smrg GLXDrawable read, GLXContext gc_user) 192848b8605Smrg{ 193848b8605Smrg struct glx_context *gc = (struct glx_context *) gc_user; 194848b8605Smrg struct glx_context *oldGC = __glXGetCurrentContext(); 195848b8605Smrg 196848b8605Smrg /* Make sure that the new context has a nonzero ID. In the request, 197848b8605Smrg * a zero context ID is used only to mean that we bind to no current 198848b8605Smrg * context. 199848b8605Smrg */ 200848b8605Smrg if ((gc != NULL) && (gc->xid == None)) { 201848b8605Smrg return GL_FALSE; 202848b8605Smrg } 203848b8605Smrg 204848b8605Smrg _glapi_check_multithread(); 205848b8605Smrg 206848b8605Smrg __glXLock(); 207848b8605Smrg if (oldGC == gc && 208848b8605Smrg gc->currentDrawable == draw && gc->currentReadable == read) { 209848b8605Smrg __glXUnlock(); 210848b8605Smrg return True; 211848b8605Smrg } 212848b8605Smrg 213b8e80941Smrg /* can't have only one be 0 */ 214b8e80941Smrg if (!!draw != !!read) { 215b8e80941Smrg __glXUnlock(); 216b8e80941Smrg __glXSendError(dpy, BadMatch, None, X_GLXMakeContextCurrent, True); 217b8e80941Smrg return False; 218b8e80941Smrg } 219b8e80941Smrg 220848b8605Smrg if (oldGC != &dummyContext) { 221848b8605Smrg if (--oldGC->thread_refcount == 0) { 222848b8605Smrg oldGC->vtable->unbind(oldGC, gc); 223848b8605Smrg oldGC->currentDpy = 0; 224848b8605Smrg } 225848b8605Smrg } 226848b8605Smrg 227848b8605Smrg if (gc) { 228848b8605Smrg /* Attempt to bind the context. We do this before mucking with 229848b8605Smrg * gc and __glXSetCurrentContext to properly handle our state in 230848b8605Smrg * case of an error. 231848b8605Smrg * 232848b8605Smrg * If an error occurs, set the Null context since we've already 233848b8605Smrg * blown away our old context. The caller is responsible for 234848b8605Smrg * figuring out how to handle setting a valid context. 235848b8605Smrg */ 236848b8605Smrg if (gc->vtable->bind(gc, oldGC, draw, read) != Success) { 237848b8605Smrg __glXSetCurrentContextNull(); 238848b8605Smrg __glXUnlock(); 239b8e80941Smrg __glXSendError(dpy, GLXBadContext, None, X_GLXMakeContextCurrent, 240b8e80941Smrg False); 241848b8605Smrg return GL_FALSE; 242848b8605Smrg } 243848b8605Smrg 244848b8605Smrg if (gc->thread_refcount == 0) { 245848b8605Smrg gc->currentDpy = dpy; 246848b8605Smrg gc->currentDrawable = draw; 247848b8605Smrg gc->currentReadable = read; 248848b8605Smrg } 249848b8605Smrg gc->thread_refcount++; 250848b8605Smrg __glXSetCurrentContext(gc); 251848b8605Smrg } else { 252848b8605Smrg __glXSetCurrentContextNull(); 253848b8605Smrg } 254848b8605Smrg 255848b8605Smrg if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) { 256848b8605Smrg /* We are switching away from a context that was 257848b8605Smrg * previously destroyed, so we need to free the memory 258848b8605Smrg * for the old handle. */ 259848b8605Smrg oldGC->vtable->destroy(oldGC); 260848b8605Smrg } 261848b8605Smrg 262848b8605Smrg __glXUnlock(); 263848b8605Smrg 264b8e80941Smrg /* The indirect vertex array state must to be initialised after we 265b8e80941Smrg * have setup the context, as it needs to query server attributes. 266b8e80941Smrg */ 267b8e80941Smrg if (gc && !gc->isDirect) { 268b8e80941Smrg __GLXattribute *state = gc->client_state_private; 269b8e80941Smrg if (state && state->array_state == NULL) { 270b8e80941Smrg glGetString(GL_EXTENSIONS); 271b8e80941Smrg glGetString(GL_VERSION); 272b8e80941Smrg __glXInitVertexArrayState(gc); 273b8e80941Smrg } 274b8e80941Smrg } 275b8e80941Smrg 276848b8605Smrg return GL_TRUE; 277848b8605Smrg} 278848b8605Smrg 279848b8605Smrg 280b8e80941Smrg_GLX_PUBLIC Bool 281848b8605SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc) 282848b8605Smrg{ 283848b8605Smrg return MakeContextCurrent(dpy, draw, draw, gc); 284848b8605Smrg} 285848b8605Smrg 286b8e80941Smrg_GLX_PUBLIC 287848b8605SmrgGLX_ALIAS(Bool, glXMakeCurrentReadSGI, 288848b8605Smrg (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx), 289848b8605Smrg (dpy, d, r, ctx), MakeContextCurrent) 290848b8605Smrg 291b8e80941Smrg_GLX_PUBLIC 292848b8605SmrgGLX_ALIAS(Bool, glXMakeContextCurrent, 293848b8605Smrg (Display * dpy, GLXDrawable d, GLXDrawable r, 294848b8605Smrg GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent) 295