glxcurrent.c revision 1463c08d
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#include <pthread.h> 37cdc920a0Smrg 38cdc920a0Smrg#include "glxclient.h" 393464ebd5Sriastradh#include "glapi.h" 4001e04c3fSmrg#include "glx_error.h" 413464ebd5Sriastradh 42e81a0f50Smaya/* 43e81a0f50Smaya * MASSIVE KLUDGE! 44e81a0f50Smaya * We need these to not be extern in libGL.so because of 45e81a0f50Smaya * PR toolchain/50277 46e81a0f50Smaya */ 47e81a0f50Smaya#if defined(GLX_USE_TLS) && defined(__NetBSD__) 48e81a0f50Smaya_X_EXPORT __thread struct _glapi_table * _glapi_tls_Dispatch 49e81a0f50Smaya __attribute__((tls_model("initial-exec"))) = NULL; 50e81a0f50Smaya_X_EXPORT __thread void * _glapi_tls_Context 51e81a0f50Smaya __attribute__((tls_model("initial-exec"))); 52e81a0f50Smaya#endif 53e81a0f50Smaya 54cdc920a0Smrg/* 55cdc920a0Smrg** We setup some dummy structures here so that the API can be used 56cdc920a0Smrg** even if no context is current. 57cdc920a0Smrg*/ 58cdc920a0Smrg 59cdc920a0Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE]; 603464ebd5Sriastradhstatic struct glx_context_vtable dummyVtable; 61cdc920a0Smrg/* 62cdc920a0Smrg** Dummy context used by small commands when there is no current context. 63cdc920a0Smrg** All the 64cdc920a0Smrg** gl and glx entry points are designed to operate as nop's when using 65cdc920a0Smrg** the dummy context structure. 66cdc920a0Smrg*/ 673464ebd5Sriastradhstruct glx_context dummyContext = { 68cdc920a0Smrg &dummyBuffer[0], 69cdc920a0Smrg &dummyBuffer[0], 70cdc920a0Smrg &dummyBuffer[0], 71cdc920a0Smrg &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE], 72cdc920a0Smrg sizeof(dummyBuffer), 733464ebd5Sriastradh &dummyVtable 74cdc920a0Smrg}; 75cdc920a0Smrg 76cdc920a0Smrg/* 77cdc920a0Smrg * Current context management and locking 78cdc920a0Smrg */ 79cdc920a0Smrg 80cdc920a0Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; 81cdc920a0Smrg 821463c08dSmrg# if defined( USE_ELF_TLS ) 83cdc920a0Smrg 84cdc920a0Smrg/** 85cdc920a0Smrg * Per-thread GLX context pointer. 86cdc920a0Smrg * 87cdc920a0Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can 88cdc920a0Smrg * \b never be \c NULL. This is important! Because of this 89cdc920a0Smrg * \c __glXGetCurrentContext can be implemented as trivial macro. 90cdc920a0Smrg */ 911463c08dSmrg__THREAD_INITIAL_EXEC void *__glX_tls_Context 92e81a0f50Smaya#if defined(__NetBSD__) 93e81a0f50Smaya = NULL; /* non-zero initializers not supported with dlopen */ 94e81a0f50Smaya#else 95cdc920a0Smrg = &dummyContext; 96e81a0f50Smaya#endif 97cdc920a0Smrg 98cdc920a0Smrg_X_HIDDEN void 993464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c) 100cdc920a0Smrg{ 101cdc920a0Smrg __glX_tls_Context = (c != NULL) ? c : &dummyContext; 102cdc920a0Smrg} 103cdc920a0Smrg 104cdc920a0Smrg# else 105cdc920a0Smrg 106cdc920a0Smrgstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 107cdc920a0Smrg 108cdc920a0Smrg/** 109cdc920a0Smrg * Per-thread data key. 110cdc920a0Smrg * 111cdc920a0Smrg * Once \c init_thread_data has been called, the per-thread data key will 112cdc920a0Smrg * take a value of \c NULL. As each new thread is created the default 113cdc920a0Smrg * value, in that thread, will be \c NULL. 114cdc920a0Smrg */ 115cdc920a0Smrgstatic pthread_key_t ContextTSD; 116cdc920a0Smrg 117cdc920a0Smrg/** 118cdc920a0Smrg * Initialize the per-thread data key. 119cdc920a0Smrg * 120cdc920a0Smrg * This function is called \b exactly once per-process (not per-thread!) to 121cdc920a0Smrg * initialize the per-thread data key. This is ideally done using the 122cdc920a0Smrg * \c pthread_once mechanism. 123cdc920a0Smrg */ 124cdc920a0Smrgstatic void 125cdc920a0Smrginit_thread_data(void) 126cdc920a0Smrg{ 127cdc920a0Smrg if (pthread_key_create(&ContextTSD, NULL) != 0) { 128cdc920a0Smrg perror("pthread_key_create"); 129cdc920a0Smrg exit(-1); 130cdc920a0Smrg } 131cdc920a0Smrg} 132cdc920a0Smrg 133cdc920a0Smrg_X_HIDDEN void 1343464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c) 135cdc920a0Smrg{ 136cdc920a0Smrg pthread_once(&once_control, init_thread_data); 137cdc920a0Smrg pthread_setspecific(ContextTSD, c); 138cdc920a0Smrg} 139cdc920a0Smrg 1403464ebd5Sriastradh_X_HIDDEN struct glx_context * 141cdc920a0Smrg__glXGetCurrentContext(void) 142cdc920a0Smrg{ 143cdc920a0Smrg void *v; 144cdc920a0Smrg 145cdc920a0Smrg pthread_once(&once_control, init_thread_data); 146cdc920a0Smrg 147cdc920a0Smrg v = pthread_getspecific(ContextTSD); 1483464ebd5Sriastradh return (v == NULL) ? &dummyContext : (struct glx_context *) v; 149cdc920a0Smrg} 150cdc920a0Smrg 1511463c08dSmrg# endif /* defined( USE_ELF_TLS ) */ 152cdc920a0Smrg 153cdc920a0Smrg 154cdc920a0Smrg_X_HIDDEN void 155cdc920a0Smrg__glXSetCurrentContextNull(void) 156cdc920a0Smrg{ 157cdc920a0Smrg __glXSetCurrentContext(&dummyContext); 1583464ebd5Sriastradh#if defined(GLX_DIRECT_RENDERING) 159cdc920a0Smrg _glapi_set_dispatch(NULL); /* no-op functions */ 160cdc920a0Smrg _glapi_set_context(NULL); 161cdc920a0Smrg#endif 162cdc920a0Smrg} 163cdc920a0Smrg 16401e04c3fSmrg_GLX_PUBLIC GLXContext 165cdc920a0SmrgglXGetCurrentContext(void) 166cdc920a0Smrg{ 1673464ebd5Sriastradh struct glx_context *cx = __glXGetCurrentContext(); 168cdc920a0Smrg 169cdc920a0Smrg if (cx == &dummyContext) { 170cdc920a0Smrg return NULL; 171cdc920a0Smrg } 172cdc920a0Smrg else { 1733464ebd5Sriastradh return (GLXContext) cx; 174cdc920a0Smrg } 175cdc920a0Smrg} 176cdc920a0Smrg 17701e04c3fSmrg_GLX_PUBLIC GLXDrawable 178cdc920a0SmrgglXGetCurrentDrawable(void) 179cdc920a0Smrg{ 1803464ebd5Sriastradh struct glx_context *gc = __glXGetCurrentContext(); 181cdc920a0Smrg return gc->currentDrawable; 182cdc920a0Smrg} 183cdc920a0Smrg 184cdc920a0Smrg/** 185cdc920a0Smrg * Make a particular context current. 186cdc920a0Smrg * 187cdc920a0Smrg * \note This is in this file so that it can access dummyContext. 188cdc920a0Smrg */ 189cdc920a0Smrgstatic Bool 190cdc920a0SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw, 1911463c08dSmrg GLXDrawable read, GLXContext gc_user, 1921463c08dSmrg int opcode) 193cdc920a0Smrg{ 1943464ebd5Sriastradh struct glx_context *gc = (struct glx_context *) gc_user; 1953464ebd5Sriastradh struct glx_context *oldGC = __glXGetCurrentContext(); 1963464ebd5Sriastradh 197cdc920a0Smrg /* Make sure that the new context has a nonzero ID. In the request, 198cdc920a0Smrg * a zero context ID is used only to mean that we bind to no current 199cdc920a0Smrg * context. 200cdc920a0Smrg */ 201cdc920a0Smrg if ((gc != NULL) && (gc->xid == None)) { 202cdc920a0Smrg return GL_FALSE; 203cdc920a0Smrg } 204cdc920a0Smrg 205cdc920a0Smrg _glapi_check_multithread(); 206cdc920a0Smrg 2073464ebd5Sriastradh __glXLock(); 2083464ebd5Sriastradh if (oldGC == gc && 2093464ebd5Sriastradh gc->currentDrawable == draw && gc->currentReadable == read) { 2103464ebd5Sriastradh __glXUnlock(); 2113464ebd5Sriastradh return True; 212cdc920a0Smrg } 213cdc920a0Smrg 21401e04c3fSmrg /* can't have only one be 0 */ 21501e04c3fSmrg if (!!draw != !!read) { 21601e04c3fSmrg __glXUnlock(); 2171463c08dSmrg __glXSendError(dpy, BadMatch, None, opcode, True); 21801e04c3fSmrg return False; 21901e04c3fSmrg } 22001e04c3fSmrg 2213464ebd5Sriastradh if (oldGC != &dummyContext) { 2223464ebd5Sriastradh if (--oldGC->thread_refcount == 0) { 2233464ebd5Sriastradh oldGC->vtable->unbind(oldGC, gc); 2243464ebd5Sriastradh oldGC->currentDpy = 0; 225cdc920a0Smrg } 226cdc920a0Smrg } 227cdc920a0Smrg 2283464ebd5Sriastradh if (gc) { 2293464ebd5Sriastradh /* Attempt to bind the context. We do this before mucking with 2303464ebd5Sriastradh * gc and __glXSetCurrentContext to properly handle our state in 2313464ebd5Sriastradh * case of an error. 2323464ebd5Sriastradh * 2333464ebd5Sriastradh * If an error occurs, set the Null context since we've already 2343464ebd5Sriastradh * blown away our old context. The caller is responsible for 2353464ebd5Sriastradh * figuring out how to handle setting a valid context. 236cdc920a0Smrg */ 2373464ebd5Sriastradh if (gc->vtable->bind(gc, oldGC, draw, read) != Success) { 2383464ebd5Sriastradh __glXSetCurrentContextNull(); 2393464ebd5Sriastradh __glXUnlock(); 2401463c08dSmrg __glXSendError(dpy, GLXBadContext, None, opcode, False); 2413464ebd5Sriastradh return GL_FALSE; 242cdc920a0Smrg } 243cdc920a0Smrg 2443464ebd5Sriastradh if (gc->thread_refcount == 0) { 245cdc920a0Smrg gc->currentDpy = dpy; 246cdc920a0Smrg gc->currentDrawable = draw; 247cdc920a0Smrg gc->currentReadable = read; 248cdc920a0Smrg } 2493464ebd5Sriastradh gc->thread_refcount++; 2503464ebd5Sriastradh __glXSetCurrentContext(gc); 2513464ebd5Sriastradh } else { 2523464ebd5Sriastradh __glXSetCurrentContextNull(); 2533464ebd5Sriastradh } 2543464ebd5Sriastradh 2553464ebd5Sriastradh if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) { 2563464ebd5Sriastradh /* We are switching away from a context that was 2573464ebd5Sriastradh * previously destroyed, so we need to free the memory 2583464ebd5Sriastradh * for the old handle. */ 2593464ebd5Sriastradh oldGC->vtable->destroy(oldGC); 260cdc920a0Smrg } 2613464ebd5Sriastradh 262cdc920a0Smrg __glXUnlock(); 2633464ebd5Sriastradh 264cdc920a0Smrg return GL_TRUE; 265cdc920a0Smrg} 266cdc920a0Smrg 26701e04c3fSmrg_GLX_PUBLIC Bool 268cdc920a0SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc) 269cdc920a0Smrg{ 2701463c08dSmrg return MakeContextCurrent(dpy, draw, draw, gc, X_GLXMakeCurrent); 271cdc920a0Smrg} 272cdc920a0Smrg 2731463c08dSmrg_GLX_PUBLIC Bool 2741463c08dSmrgglXMakeContextCurrent(Display *dpy, GLXDrawable d, GLXDrawable r, 2751463c08dSmrg GLXContext ctx) 2761463c08dSmrg{ 2771463c08dSmrg return MakeContextCurrent(dpy, d, r, ctx, X_GLXMakeContextCurrent); 2781463c08dSmrg} 279cdc920a0Smrg 2801463c08dSmrg_GLX_PUBLIC Bool 2811463c08dSmrgglXMakeCurrentReadSGI(Display *dpy, GLXDrawable d, GLXDrawable r, 2821463c08dSmrg GLXContext ctx) 2831463c08dSmrg{ 2841463c08dSmrg return MakeContextCurrent(dpy, d, r, ctx, X_GLXvop_MakeCurrentReadSGI); 2851463c08dSmrg} 286