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 42cdc920a0Smrg/* 43cdc920a0Smrg** We setup some dummy structures here so that the API can be used 44cdc920a0Smrg** even if no context is current. 45cdc920a0Smrg*/ 46cdc920a0Smrg 47cdc920a0Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE]; 483464ebd5Sriastradhstatic struct glx_context_vtable dummyVtable; 49cdc920a0Smrg/* 50cdc920a0Smrg** Dummy context used by small commands when there is no current context. 51cdc920a0Smrg** All the 52cdc920a0Smrg** gl and glx entry points are designed to operate as nop's when using 53cdc920a0Smrg** the dummy context structure. 54cdc920a0Smrg*/ 553464ebd5Sriastradhstruct glx_context dummyContext = { 56cdc920a0Smrg &dummyBuffer[0], 57cdc920a0Smrg &dummyBuffer[0], 58cdc920a0Smrg &dummyBuffer[0], 59cdc920a0Smrg &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE], 60cdc920a0Smrg sizeof(dummyBuffer), 613464ebd5Sriastradh &dummyVtable 62cdc920a0Smrg}; 63cdc920a0Smrg 64cdc920a0Smrg/* 65cdc920a0Smrg * Current context management and locking 66cdc920a0Smrg */ 67cdc920a0Smrg 68cdc920a0Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; 69cdc920a0Smrg 701463c08dSmrg# if defined( USE_ELF_TLS ) 71cdc920a0Smrg 72cdc920a0Smrg/** 73cdc920a0Smrg * Per-thread GLX context pointer. 74cdc920a0Smrg * 75cdc920a0Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can 76cdc920a0Smrg * \b never be \c NULL. This is important! Because of this 77cdc920a0Smrg * \c __glXGetCurrentContext can be implemented as trivial macro. 78cdc920a0Smrg */ 791463c08dSmrg__THREAD_INITIAL_EXEC void *__glX_tls_Context 80e81a0f50Smaya#if defined(__NetBSD__) 81e81a0f50Smaya = NULL; /* non-zero initializers not supported with dlopen */ 82e81a0f50Smaya#else 83cdc920a0Smrg = &dummyContext; 84e81a0f50Smaya#endif 85cdc920a0Smrg 86cdc920a0Smrg_X_HIDDEN void 873464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c) 88cdc920a0Smrg{ 89cdc920a0Smrg __glX_tls_Context = (c != NULL) ? c : &dummyContext; 90cdc920a0Smrg} 91cdc920a0Smrg 92cdc920a0Smrg# else 93cdc920a0Smrg 94cdc920a0Smrgstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 95cdc920a0Smrg 96cdc920a0Smrg/** 97cdc920a0Smrg * Per-thread data key. 98cdc920a0Smrg * 99cdc920a0Smrg * Once \c init_thread_data has been called, the per-thread data key will 100cdc920a0Smrg * take a value of \c NULL. As each new thread is created the default 101cdc920a0Smrg * value, in that thread, will be \c NULL. 102cdc920a0Smrg */ 103cdc920a0Smrgstatic pthread_key_t ContextTSD; 104cdc920a0Smrg 105cdc920a0Smrg/** 106cdc920a0Smrg * Initialize the per-thread data key. 107cdc920a0Smrg * 108cdc920a0Smrg * This function is called \b exactly once per-process (not per-thread!) to 109cdc920a0Smrg * initialize the per-thread data key. This is ideally done using the 110cdc920a0Smrg * \c pthread_once mechanism. 111cdc920a0Smrg */ 112cdc920a0Smrgstatic void 113cdc920a0Smrginit_thread_data(void) 114cdc920a0Smrg{ 115cdc920a0Smrg if (pthread_key_create(&ContextTSD, NULL) != 0) { 116cdc920a0Smrg perror("pthread_key_create"); 117cdc920a0Smrg exit(-1); 118cdc920a0Smrg } 119cdc920a0Smrg} 120cdc920a0Smrg 121cdc920a0Smrg_X_HIDDEN void 1223464ebd5Sriastradh__glXSetCurrentContext(struct glx_context * c) 123cdc920a0Smrg{ 124cdc920a0Smrg pthread_once(&once_control, init_thread_data); 125cdc920a0Smrg pthread_setspecific(ContextTSD, c); 126cdc920a0Smrg} 127cdc920a0Smrg 1283464ebd5Sriastradh_X_HIDDEN struct glx_context * 129cdc920a0Smrg__glXGetCurrentContext(void) 130cdc920a0Smrg{ 131cdc920a0Smrg void *v; 132cdc920a0Smrg 133cdc920a0Smrg pthread_once(&once_control, init_thread_data); 134cdc920a0Smrg 135cdc920a0Smrg v = pthread_getspecific(ContextTSD); 1363464ebd5Sriastradh return (v == NULL) ? &dummyContext : (struct glx_context *) v; 137cdc920a0Smrg} 138cdc920a0Smrg 1391463c08dSmrg# endif /* defined( USE_ELF_TLS ) */ 140cdc920a0Smrg 141cdc920a0Smrg 142cdc920a0Smrg_X_HIDDEN void 143cdc920a0Smrg__glXSetCurrentContextNull(void) 144cdc920a0Smrg{ 145cdc920a0Smrg __glXSetCurrentContext(&dummyContext); 1463464ebd5Sriastradh#if defined(GLX_DIRECT_RENDERING) 147cdc920a0Smrg _glapi_set_dispatch(NULL); /* no-op functions */ 148cdc920a0Smrg _glapi_set_context(NULL); 149cdc920a0Smrg#endif 150cdc920a0Smrg} 151cdc920a0Smrg 15201e04c3fSmrg_GLX_PUBLIC GLXContext 153cdc920a0SmrgglXGetCurrentContext(void) 154cdc920a0Smrg{ 1553464ebd5Sriastradh struct glx_context *cx = __glXGetCurrentContext(); 156cdc920a0Smrg 157cdc920a0Smrg if (cx == &dummyContext) { 158cdc920a0Smrg return NULL; 159cdc920a0Smrg } 160cdc920a0Smrg else { 1613464ebd5Sriastradh return (GLXContext) cx; 162cdc920a0Smrg } 163cdc920a0Smrg} 164cdc920a0Smrg 16501e04c3fSmrg_GLX_PUBLIC GLXDrawable 166cdc920a0SmrgglXGetCurrentDrawable(void) 167cdc920a0Smrg{ 1683464ebd5Sriastradh struct glx_context *gc = __glXGetCurrentContext(); 169cdc920a0Smrg return gc->currentDrawable; 170cdc920a0Smrg} 171cdc920a0Smrg 172cdc920a0Smrg/** 173cdc920a0Smrg * Make a particular context current. 174cdc920a0Smrg * 175cdc920a0Smrg * \note This is in this file so that it can access dummyContext. 176cdc920a0Smrg */ 177cdc920a0Smrgstatic Bool 178cdc920a0SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw, 1791463c08dSmrg GLXDrawable read, GLXContext gc_user, 1801463c08dSmrg int opcode) 181cdc920a0Smrg{ 1823464ebd5Sriastradh struct glx_context *gc = (struct glx_context *) gc_user; 1833464ebd5Sriastradh struct glx_context *oldGC = __glXGetCurrentContext(); 1843464ebd5Sriastradh 185cdc920a0Smrg /* Make sure that the new context has a nonzero ID. In the request, 186cdc920a0Smrg * a zero context ID is used only to mean that we bind to no current 187cdc920a0Smrg * context. 188cdc920a0Smrg */ 189cdc920a0Smrg if ((gc != NULL) && (gc->xid == None)) { 190cdc920a0Smrg return GL_FALSE; 191cdc920a0Smrg } 192cdc920a0Smrg 193cdc920a0Smrg _glapi_check_multithread(); 194cdc920a0Smrg 1953464ebd5Sriastradh __glXLock(); 1963464ebd5Sriastradh if (oldGC == gc && 1973464ebd5Sriastradh gc->currentDrawable == draw && gc->currentReadable == read) { 1983464ebd5Sriastradh __glXUnlock(); 1993464ebd5Sriastradh return True; 200cdc920a0Smrg } 201cdc920a0Smrg 20201e04c3fSmrg /* can't have only one be 0 */ 20301e04c3fSmrg if (!!draw != !!read) { 20401e04c3fSmrg __glXUnlock(); 2051463c08dSmrg __glXSendError(dpy, BadMatch, None, opcode, True); 20601e04c3fSmrg return False; 20701e04c3fSmrg } 20801e04c3fSmrg 2093464ebd5Sriastradh if (oldGC != &dummyContext) { 2103464ebd5Sriastradh if (--oldGC->thread_refcount == 0) { 2113464ebd5Sriastradh oldGC->vtable->unbind(oldGC, gc); 2123464ebd5Sriastradh oldGC->currentDpy = 0; 213cdc920a0Smrg } 214cdc920a0Smrg } 215cdc920a0Smrg 2163464ebd5Sriastradh if (gc) { 2173464ebd5Sriastradh /* Attempt to bind the context. We do this before mucking with 2183464ebd5Sriastradh * gc and __glXSetCurrentContext to properly handle our state in 2193464ebd5Sriastradh * case of an error. 2203464ebd5Sriastradh * 2213464ebd5Sriastradh * If an error occurs, set the Null context since we've already 2223464ebd5Sriastradh * blown away our old context. The caller is responsible for 2233464ebd5Sriastradh * figuring out how to handle setting a valid context. 224cdc920a0Smrg */ 2253464ebd5Sriastradh if (gc->vtable->bind(gc, oldGC, draw, read) != Success) { 2263464ebd5Sriastradh __glXSetCurrentContextNull(); 2273464ebd5Sriastradh __glXUnlock(); 2281463c08dSmrg __glXSendError(dpy, GLXBadContext, None, opcode, False); 2293464ebd5Sriastradh return GL_FALSE; 230cdc920a0Smrg } 231cdc920a0Smrg 2323464ebd5Sriastradh if (gc->thread_refcount == 0) { 233cdc920a0Smrg gc->currentDpy = dpy; 234cdc920a0Smrg gc->currentDrawable = draw; 235cdc920a0Smrg gc->currentReadable = read; 236cdc920a0Smrg } 2373464ebd5Sriastradh gc->thread_refcount++; 2383464ebd5Sriastradh __glXSetCurrentContext(gc); 2393464ebd5Sriastradh } else { 2403464ebd5Sriastradh __glXSetCurrentContextNull(); 2413464ebd5Sriastradh } 2423464ebd5Sriastradh 2433464ebd5Sriastradh if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) { 2443464ebd5Sriastradh /* We are switching away from a context that was 2453464ebd5Sriastradh * previously destroyed, so we need to free the memory 2463464ebd5Sriastradh * for the old handle. */ 2473464ebd5Sriastradh oldGC->vtable->destroy(oldGC); 248cdc920a0Smrg } 2493464ebd5Sriastradh 250cdc920a0Smrg __glXUnlock(); 2513464ebd5Sriastradh 252cdc920a0Smrg return GL_TRUE; 253cdc920a0Smrg} 254cdc920a0Smrg 25501e04c3fSmrg_GLX_PUBLIC Bool 256cdc920a0SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc) 257cdc920a0Smrg{ 2581463c08dSmrg return MakeContextCurrent(dpy, draw, draw, gc, X_GLXMakeCurrent); 259cdc920a0Smrg} 260cdc920a0Smrg 2611463c08dSmrg_GLX_PUBLIC Bool 2621463c08dSmrgglXMakeContextCurrent(Display *dpy, GLXDrawable d, GLXDrawable r, 2631463c08dSmrg GLXContext ctx) 2641463c08dSmrg{ 2651463c08dSmrg return MakeContextCurrent(dpy, d, r, ctx, X_GLXMakeContextCurrent); 2661463c08dSmrg} 267cdc920a0Smrg 2681463c08dSmrg_GLX_PUBLIC Bool 2691463c08dSmrgglXMakeCurrentReadSGI(Display *dpy, GLXDrawable d, GLXDrawable r, 2701463c08dSmrg GLXContext ctx) 2711463c08dSmrg{ 2721463c08dSmrg return MakeContextCurrent(dpy, d, r, ctx, X_GLXvop_MakeCurrentReadSGI); 2731463c08dSmrg} 274