glxcurrent.c revision 848b8605
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#ifdef HAVE_PTHREAD 37848b8605Smrg#include <pthread.h> 38848b8605Smrg#endif 39848b8605Smrg 40848b8605Smrg#include "glxclient.h" 41848b8605Smrg 42848b8605Smrg#include "glapi.h" 43848b8605Smrg 44848b8605Smrg/* 45848b8605Smrg** We setup some dummy structures here so that the API can be used 46848b8605Smrg** even if no context is current. 47848b8605Smrg*/ 48848b8605Smrg 49848b8605Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE]; 50848b8605Smrgstatic struct glx_context_vtable dummyVtable; 51848b8605Smrg/* 52848b8605Smrg** Dummy context used by small commands when there is no current context. 53848b8605Smrg** All the 54848b8605Smrg** gl and glx entry points are designed to operate as nop's when using 55848b8605Smrg** the dummy context structure. 56848b8605Smrg*/ 57848b8605Smrgstruct glx_context dummyContext = { 58848b8605Smrg &dummyBuffer[0], 59848b8605Smrg &dummyBuffer[0], 60848b8605Smrg &dummyBuffer[0], 61848b8605Smrg &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE], 62848b8605Smrg sizeof(dummyBuffer), 63848b8605Smrg &dummyVtable 64848b8605Smrg}; 65848b8605Smrg 66848b8605Smrg/* 67848b8605Smrg * Current context management and locking 68848b8605Smrg */ 69848b8605Smrg 70848b8605Smrg#if defined( HAVE_PTHREAD ) 71848b8605Smrg 72848b8605Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; 73848b8605Smrg 74848b8605Smrg# if defined( GLX_USE_TLS ) 75848b8605Smrg 76848b8605Smrg/** 77848b8605Smrg * Per-thread GLX context pointer. 78848b8605Smrg * 79848b8605Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can 80848b8605Smrg * \b never be \c NULL. This is important! Because of this 81848b8605Smrg * \c __glXGetCurrentContext can be implemented as trivial macro. 82848b8605Smrg */ 83848b8605Smrg__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec"))) 84848b8605Smrg = &dummyContext; 85848b8605Smrg 86848b8605Smrg_X_HIDDEN void 87848b8605Smrg__glXSetCurrentContext(struct glx_context * c) 88848b8605Smrg{ 89848b8605Smrg __glX_tls_Context = (c != NULL) ? c : &dummyContext; 90848b8605Smrg} 91848b8605Smrg 92848b8605Smrg# else 93848b8605Smrg 94848b8605Smrgstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 95848b8605Smrg 96848b8605Smrg/** 97848b8605Smrg * Per-thread data key. 98848b8605Smrg * 99848b8605Smrg * Once \c init_thread_data has been called, the per-thread data key will 100848b8605Smrg * take a value of \c NULL. As each new thread is created the default 101848b8605Smrg * value, in that thread, will be \c NULL. 102848b8605Smrg */ 103848b8605Smrgstatic pthread_key_t ContextTSD; 104848b8605Smrg 105848b8605Smrg/** 106848b8605Smrg * Initialize the per-thread data key. 107848b8605Smrg * 108848b8605Smrg * This function is called \b exactly once per-process (not per-thread!) to 109848b8605Smrg * initialize the per-thread data key. This is ideally done using the 110848b8605Smrg * \c pthread_once mechanism. 111848b8605Smrg */ 112848b8605Smrgstatic void 113848b8605Smrginit_thread_data(void) 114848b8605Smrg{ 115848b8605Smrg if (pthread_key_create(&ContextTSD, NULL) != 0) { 116848b8605Smrg perror("pthread_key_create"); 117848b8605Smrg exit(-1); 118848b8605Smrg } 119848b8605Smrg} 120848b8605Smrg 121848b8605Smrg_X_HIDDEN void 122848b8605Smrg__glXSetCurrentContext(struct glx_context * c) 123848b8605Smrg{ 124848b8605Smrg pthread_once(&once_control, init_thread_data); 125848b8605Smrg pthread_setspecific(ContextTSD, c); 126848b8605Smrg} 127848b8605Smrg 128848b8605Smrg_X_HIDDEN struct glx_context * 129848b8605Smrg__glXGetCurrentContext(void) 130848b8605Smrg{ 131848b8605Smrg void *v; 132848b8605Smrg 133848b8605Smrg pthread_once(&once_control, init_thread_data); 134848b8605Smrg 135848b8605Smrg v = pthread_getspecific(ContextTSD); 136848b8605Smrg return (v == NULL) ? &dummyContext : (struct glx_context *) v; 137848b8605Smrg} 138848b8605Smrg 139848b8605Smrg# endif /* defined( GLX_USE_TLS ) */ 140848b8605Smrg 141848b8605Smrg#elif defined( THREADS ) 142848b8605Smrg 143848b8605Smrg#error Unknown threading method specified. 144848b8605Smrg 145848b8605Smrg#else 146848b8605Smrg 147848b8605Smrg/* not thread safe */ 148848b8605Smrg_X_HIDDEN struct glx_context *__glXcurrentContext = &dummyContext; 149848b8605Smrg 150848b8605Smrg#endif 151848b8605Smrg 152848b8605Smrg 153848b8605Smrg_X_HIDDEN void 154848b8605Smrg__glXSetCurrentContextNull(void) 155848b8605Smrg{ 156848b8605Smrg __glXSetCurrentContext(&dummyContext); 157848b8605Smrg#if defined(GLX_DIRECT_RENDERING) 158848b8605Smrg _glapi_set_dispatch(NULL); /* no-op functions */ 159848b8605Smrg _glapi_set_context(NULL); 160848b8605Smrg#endif 161848b8605Smrg} 162848b8605Smrg 163848b8605Smrg_X_EXPORT GLXContext 164848b8605SmrgglXGetCurrentContext(void) 165848b8605Smrg{ 166848b8605Smrg struct glx_context *cx = __glXGetCurrentContext(); 167848b8605Smrg 168848b8605Smrg if (cx == &dummyContext) { 169848b8605Smrg return NULL; 170848b8605Smrg } 171848b8605Smrg else { 172848b8605Smrg return (GLXContext) cx; 173848b8605Smrg } 174848b8605Smrg} 175848b8605Smrg 176848b8605Smrg_X_EXPORT GLXDrawable 177848b8605SmrgglXGetCurrentDrawable(void) 178848b8605Smrg{ 179848b8605Smrg struct glx_context *gc = __glXGetCurrentContext(); 180848b8605Smrg return gc->currentDrawable; 181848b8605Smrg} 182848b8605Smrg 183848b8605Smrgstatic void 184848b8605Smrg__glXGenerateError(Display * dpy, XID resource, 185848b8605Smrg BYTE errorCode, CARD16 minorCode) 186848b8605Smrg{ 187848b8605Smrg xError error; 188848b8605Smrg 189848b8605Smrg error.errorCode = errorCode; 190848b8605Smrg error.resourceID = resource; 191848b8605Smrg error.sequenceNumber = dpy->request; 192848b8605Smrg error.type = X_Error; 193848b8605Smrg error.majorCode = __glXSetupForCommand(dpy); 194848b8605Smrg error.minorCode = minorCode; 195848b8605Smrg _XError(dpy, &error); 196848b8605Smrg} 197848b8605Smrg 198848b8605Smrg/** 199848b8605Smrg * Make a particular context current. 200848b8605Smrg * 201848b8605Smrg * \note This is in this file so that it can access dummyContext. 202848b8605Smrg */ 203848b8605Smrgstatic Bool 204848b8605SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw, 205848b8605Smrg GLXDrawable read, GLXContext gc_user) 206848b8605Smrg{ 207848b8605Smrg struct glx_context *gc = (struct glx_context *) gc_user; 208848b8605Smrg struct glx_context *oldGC = __glXGetCurrentContext(); 209848b8605Smrg 210848b8605Smrg /* Make sure that the new context has a nonzero ID. In the request, 211848b8605Smrg * a zero context ID is used only to mean that we bind to no current 212848b8605Smrg * context. 213848b8605Smrg */ 214848b8605Smrg if ((gc != NULL) && (gc->xid == None)) { 215848b8605Smrg return GL_FALSE; 216848b8605Smrg } 217848b8605Smrg 218848b8605Smrg _glapi_check_multithread(); 219848b8605Smrg 220848b8605Smrg __glXLock(); 221848b8605Smrg if (oldGC == gc && 222848b8605Smrg gc->currentDrawable == draw && gc->currentReadable == read) { 223848b8605Smrg __glXUnlock(); 224848b8605Smrg return True; 225848b8605Smrg } 226848b8605Smrg 227848b8605Smrg if (oldGC != &dummyContext) { 228848b8605Smrg if (--oldGC->thread_refcount == 0) { 229848b8605Smrg oldGC->vtable->unbind(oldGC, gc); 230848b8605Smrg oldGC->currentDpy = 0; 231848b8605Smrg } 232848b8605Smrg } 233848b8605Smrg 234848b8605Smrg if (gc) { 235848b8605Smrg /* Attempt to bind the context. We do this before mucking with 236848b8605Smrg * gc and __glXSetCurrentContext to properly handle our state in 237848b8605Smrg * case of an error. 238848b8605Smrg * 239848b8605Smrg * If an error occurs, set the Null context since we've already 240848b8605Smrg * blown away our old context. The caller is responsible for 241848b8605Smrg * figuring out how to handle setting a valid context. 242848b8605Smrg */ 243848b8605Smrg if (gc->vtable->bind(gc, oldGC, draw, read) != Success) { 244848b8605Smrg __glXSetCurrentContextNull(); 245848b8605Smrg __glXUnlock(); 246848b8605Smrg __glXGenerateError(dpy, None, GLXBadContext, X_GLXMakeContextCurrent); 247848b8605Smrg return GL_FALSE; 248848b8605Smrg } 249848b8605Smrg 250848b8605Smrg if (gc->thread_refcount == 0) { 251848b8605Smrg gc->currentDpy = dpy; 252848b8605Smrg gc->currentDrawable = draw; 253848b8605Smrg gc->currentReadable = read; 254848b8605Smrg } 255848b8605Smrg gc->thread_refcount++; 256848b8605Smrg __glXSetCurrentContext(gc); 257848b8605Smrg } else { 258848b8605Smrg __glXSetCurrentContextNull(); 259848b8605Smrg } 260848b8605Smrg 261848b8605Smrg if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) { 262848b8605Smrg /* We are switching away from a context that was 263848b8605Smrg * previously destroyed, so we need to free the memory 264848b8605Smrg * for the old handle. */ 265848b8605Smrg oldGC->vtable->destroy(oldGC); 266848b8605Smrg } 267848b8605Smrg 268848b8605Smrg __glXUnlock(); 269848b8605Smrg 270848b8605Smrg return GL_TRUE; 271848b8605Smrg} 272848b8605Smrg 273848b8605Smrg 274848b8605Smrg_X_EXPORT Bool 275848b8605SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc) 276848b8605Smrg{ 277848b8605Smrg return MakeContextCurrent(dpy, draw, draw, gc); 278848b8605Smrg} 279848b8605Smrg 280848b8605Smrg_X_EXPORT 281848b8605SmrgGLX_ALIAS(Bool, glXMakeCurrentReadSGI, 282848b8605Smrg (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx), 283848b8605Smrg (dpy, d, r, ctx), MakeContextCurrent) 284848b8605Smrg 285848b8605Smrg_X_EXPORT 286848b8605SmrgGLX_ALIAS(Bool, glXMakeContextCurrent, 287848b8605Smrg (Display * dpy, GLXDrawable d, GLXDrawable r, 288848b8605Smrg GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent) 289