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 42848b8605Smrg/* 43848b8605Smrg** We setup some dummy structures here so that the API can be used 44848b8605Smrg** even if no context is current. 45848b8605Smrg*/ 46848b8605Smrg 47848b8605Smrgstatic GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE]; 48848b8605Smrgstatic struct glx_context_vtable dummyVtable; 49848b8605Smrg/* 50848b8605Smrg** Dummy context used by small commands when there is no current context. 51848b8605Smrg** All the 52848b8605Smrg** gl and glx entry points are designed to operate as nop's when using 53848b8605Smrg** the dummy context structure. 54848b8605Smrg*/ 55848b8605Smrgstruct glx_context dummyContext = { 56848b8605Smrg &dummyBuffer[0], 57848b8605Smrg &dummyBuffer[0], 58848b8605Smrg &dummyBuffer[0], 59848b8605Smrg &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE], 60848b8605Smrg sizeof(dummyBuffer), 61848b8605Smrg &dummyVtable 62848b8605Smrg}; 63848b8605Smrg 64848b8605Smrg/* 65848b8605Smrg * Current context management and locking 66848b8605Smrg */ 67848b8605Smrg 68848b8605Smrg_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; 69848b8605Smrg 70848b8605Smrg# if defined( GLX_USE_TLS ) 71848b8605Smrg 72848b8605Smrg/** 73848b8605Smrg * Per-thread GLX context pointer. 74848b8605Smrg * 75848b8605Smrg * \c __glXSetCurrentContext is written is such a way that this pointer can 76848b8605Smrg * \b never be \c NULL. This is important! Because of this 77848b8605Smrg * \c __glXGetCurrentContext can be implemented as trivial macro. 78848b8605Smrg */ 79848b8605Smrg__thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec"))) 80b8e80941Smrg#if defined(__NetBSD__) 81b8e80941Smrg = NULL; /* non-zero initializers not supported with dlopen */ 82b8e80941Smrg#else 83848b8605Smrg = &dummyContext; 84b8e80941Smrg#endif 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 142848b8605Smrg_X_HIDDEN void 143848b8605Smrg__glXSetCurrentContextNull(void) 144848b8605Smrg{ 145848b8605Smrg __glXSetCurrentContext(&dummyContext); 146848b8605Smrg#if defined(GLX_DIRECT_RENDERING) 147848b8605Smrg _glapi_set_dispatch(NULL); /* no-op functions */ 148848b8605Smrg _glapi_set_context(NULL); 149848b8605Smrg#endif 150848b8605Smrg} 151848b8605Smrg 152b8e80941Smrg_GLX_PUBLIC GLXContext 153848b8605SmrgglXGetCurrentContext(void) 154848b8605Smrg{ 155848b8605Smrg struct glx_context *cx = __glXGetCurrentContext(); 156848b8605Smrg 157848b8605Smrg if (cx == &dummyContext) { 158848b8605Smrg return NULL; 159848b8605Smrg } 160848b8605Smrg else { 161848b8605Smrg return (GLXContext) cx; 162848b8605Smrg } 163848b8605Smrg} 164848b8605Smrg 165b8e80941Smrg_GLX_PUBLIC GLXDrawable 166848b8605SmrgglXGetCurrentDrawable(void) 167848b8605Smrg{ 168848b8605Smrg struct glx_context *gc = __glXGetCurrentContext(); 169848b8605Smrg return gc->currentDrawable; 170848b8605Smrg} 171848b8605Smrg 172848b8605Smrg/** 173848b8605Smrg * Make a particular context current. 174848b8605Smrg * 175848b8605Smrg * \note This is in this file so that it can access dummyContext. 176848b8605Smrg */ 177848b8605Smrgstatic Bool 178848b8605SmrgMakeContextCurrent(Display * dpy, GLXDrawable draw, 179848b8605Smrg GLXDrawable read, GLXContext gc_user) 180848b8605Smrg{ 181848b8605Smrg struct glx_context *gc = (struct glx_context *) gc_user; 182848b8605Smrg struct glx_context *oldGC = __glXGetCurrentContext(); 183848b8605Smrg 184848b8605Smrg /* Make sure that the new context has a nonzero ID. In the request, 185848b8605Smrg * a zero context ID is used only to mean that we bind to no current 186848b8605Smrg * context. 187848b8605Smrg */ 188848b8605Smrg if ((gc != NULL) && (gc->xid == None)) { 189848b8605Smrg return GL_FALSE; 190848b8605Smrg } 191848b8605Smrg 192848b8605Smrg _glapi_check_multithread(); 193848b8605Smrg 194848b8605Smrg __glXLock(); 195848b8605Smrg if (oldGC == gc && 196848b8605Smrg gc->currentDrawable == draw && gc->currentReadable == read) { 197848b8605Smrg __glXUnlock(); 198848b8605Smrg return True; 199848b8605Smrg } 200848b8605Smrg 201b8e80941Smrg /* can't have only one be 0 */ 202b8e80941Smrg if (!!draw != !!read) { 203b8e80941Smrg __glXUnlock(); 204b8e80941Smrg __glXSendError(dpy, BadMatch, None, X_GLXMakeContextCurrent, True); 205b8e80941Smrg return False; 206b8e80941Smrg } 207b8e80941Smrg 208848b8605Smrg if (oldGC != &dummyContext) { 209848b8605Smrg if (--oldGC->thread_refcount == 0) { 210848b8605Smrg oldGC->vtable->unbind(oldGC, gc); 211848b8605Smrg oldGC->currentDpy = 0; 212848b8605Smrg } 213848b8605Smrg } 214848b8605Smrg 215848b8605Smrg if (gc) { 216848b8605Smrg /* Attempt to bind the context. We do this before mucking with 217848b8605Smrg * gc and __glXSetCurrentContext to properly handle our state in 218848b8605Smrg * case of an error. 219848b8605Smrg * 220848b8605Smrg * If an error occurs, set the Null context since we've already 221848b8605Smrg * blown away our old context. The caller is responsible for 222848b8605Smrg * figuring out how to handle setting a valid context. 223848b8605Smrg */ 224848b8605Smrg if (gc->vtable->bind(gc, oldGC, draw, read) != Success) { 225848b8605Smrg __glXSetCurrentContextNull(); 226848b8605Smrg __glXUnlock(); 227b8e80941Smrg __glXSendError(dpy, GLXBadContext, None, X_GLXMakeContextCurrent, 228b8e80941Smrg False); 229848b8605Smrg return GL_FALSE; 230848b8605Smrg } 231848b8605Smrg 232848b8605Smrg if (gc->thread_refcount == 0) { 233848b8605Smrg gc->currentDpy = dpy; 234848b8605Smrg gc->currentDrawable = draw; 235848b8605Smrg gc->currentReadable = read; 236848b8605Smrg } 237848b8605Smrg gc->thread_refcount++; 238848b8605Smrg __glXSetCurrentContext(gc); 239848b8605Smrg } else { 240848b8605Smrg __glXSetCurrentContextNull(); 241848b8605Smrg } 242848b8605Smrg 243848b8605Smrg if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) { 244848b8605Smrg /* We are switching away from a context that was 245848b8605Smrg * previously destroyed, so we need to free the memory 246848b8605Smrg * for the old handle. */ 247848b8605Smrg oldGC->vtable->destroy(oldGC); 248848b8605Smrg } 249848b8605Smrg 250848b8605Smrg __glXUnlock(); 251848b8605Smrg 252b8e80941Smrg /* The indirect vertex array state must to be initialised after we 253b8e80941Smrg * have setup the context, as it needs to query server attributes. 254b8e80941Smrg */ 255b8e80941Smrg if (gc && !gc->isDirect) { 256b8e80941Smrg __GLXattribute *state = gc->client_state_private; 257b8e80941Smrg if (state && state->array_state == NULL) { 258b8e80941Smrg glGetString(GL_EXTENSIONS); 259b8e80941Smrg glGetString(GL_VERSION); 260b8e80941Smrg __glXInitVertexArrayState(gc); 261b8e80941Smrg } 262b8e80941Smrg } 263b8e80941Smrg 264848b8605Smrg return GL_TRUE; 265848b8605Smrg} 266848b8605Smrg 267848b8605Smrg 268b8e80941Smrg_GLX_PUBLIC Bool 269848b8605SmrgglXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc) 270848b8605Smrg{ 271848b8605Smrg return MakeContextCurrent(dpy, draw, draw, gc); 272848b8605Smrg} 273848b8605Smrg 274b8e80941Smrg_GLX_PUBLIC 275848b8605SmrgGLX_ALIAS(Bool, glXMakeCurrentReadSGI, 276848b8605Smrg (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx), 277848b8605Smrg (dpy, d, r, ctx), MakeContextCurrent) 278848b8605Smrg 279b8e80941Smrg_GLX_PUBLIC 280848b8605SmrgGLX_ALIAS(Bool, glXMakeContextCurrent, 281848b8605Smrg (Display * dpy, GLXDrawable d, GLXDrawable r, 282848b8605Smrg GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent) 283