/*1* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)2* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice including the dates of first publication and12* either this permission notice or a reference to13* http://oss.sgi.com/projects/FreeB/14* shall be included in all copies or substantial portions of the Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS17* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL19* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,20* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF21* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE22* SOFTWARE.23*24* Except as contained in this notice, the name of Silicon Graphics, Inc.25* shall not be used in advertising or otherwise to promote the sale, use or26* other dealings in this Software without prior written authorization from27* Silicon Graphics, Inc.28*/2930/**31* \file glxcurrent.c32* Client-side GLX interface for current context management.33*/3435#include <pthread.h>3637#include "glxclient.h"38#include "glapi.h"39#include "glx_error.h"4041/*42** We setup some dummy structures here so that the API can be used43** even if no context is current.44*/4546static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];47static struct glx_context_vtable dummyVtable;48/*49** Dummy context used by small commands when there is no current context.50** All the51** gl and glx entry points are designed to operate as nop's when using52** the dummy context structure.53*/54struct glx_context dummyContext = {55&dummyBuffer[0],56&dummyBuffer[0],57&dummyBuffer[0],58&dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],59sizeof(dummyBuffer),60&dummyVtable61};6263/*64* Current context management and locking65*/6667_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;6869# if defined( USE_ELF_TLS )7071/**72* Per-thread GLX context pointer.73*74* \c __glXSetCurrentContext is written is such a way that this pointer can75* \b never be \c NULL. This is important! Because of this76* \c __glXGetCurrentContext can be implemented as trivial macro.77*/78__THREAD_INITIAL_EXEC void *__glX_tls_Context = &dummyContext;7980_X_HIDDEN void81__glXSetCurrentContext(struct glx_context * c)82{83__glX_tls_Context = (c != NULL) ? c : &dummyContext;84}8586# else8788static pthread_once_t once_control = PTHREAD_ONCE_INIT;8990/**91* Per-thread data key.92*93* Once \c init_thread_data has been called, the per-thread data key will94* take a value of \c NULL. As each new thread is created the default95* value, in that thread, will be \c NULL.96*/97static pthread_key_t ContextTSD;9899/**100* Initialize the per-thread data key.101*102* This function is called \b exactly once per-process (not per-thread!) to103* initialize the per-thread data key. This is ideally done using the104* \c pthread_once mechanism.105*/106static void107init_thread_data(void)108{109if (pthread_key_create(&ContextTSD, NULL) != 0) {110perror("pthread_key_create");111exit(-1);112}113}114115_X_HIDDEN void116__glXSetCurrentContext(struct glx_context * c)117{118pthread_once(&once_control, init_thread_data);119pthread_setspecific(ContextTSD, c);120}121122_X_HIDDEN struct glx_context *123__glXGetCurrentContext(void)124{125void *v;126127pthread_once(&once_control, init_thread_data);128129v = pthread_getspecific(ContextTSD);130return (v == NULL) ? &dummyContext : (struct glx_context *) v;131}132133# endif /* defined( USE_ELF_TLS ) */134135136_X_HIDDEN void137__glXSetCurrentContextNull(void)138{139__glXSetCurrentContext(&dummyContext);140#if defined(GLX_DIRECT_RENDERING)141_glapi_set_dispatch(NULL); /* no-op functions */142_glapi_set_context(NULL);143#endif144}145146_GLX_PUBLIC GLXContext147glXGetCurrentContext(void)148{149struct glx_context *cx = __glXGetCurrentContext();150151if (cx == &dummyContext) {152return NULL;153}154else {155return (GLXContext) cx;156}157}158159_GLX_PUBLIC GLXDrawable160glXGetCurrentDrawable(void)161{162struct glx_context *gc = __glXGetCurrentContext();163return gc->currentDrawable;164}165166/**167* Make a particular context current.168*169* \note This is in this file so that it can access dummyContext.170*/171static Bool172MakeContextCurrent(Display * dpy, GLXDrawable draw,173GLXDrawable read, GLXContext gc_user,174int opcode)175{176struct glx_context *gc = (struct glx_context *) gc_user;177struct glx_context *oldGC = __glXGetCurrentContext();178179/* Make sure that the new context has a nonzero ID. In the request,180* a zero context ID is used only to mean that we bind to no current181* context.182*/183if ((gc != NULL) && (gc->xid == None)) {184return GL_FALSE;185}186187_glapi_check_multithread();188189__glXLock();190if (oldGC == gc &&191gc->currentDrawable == draw && gc->currentReadable == read) {192__glXUnlock();193return True;194}195196/* can't have only one be 0 */197if (!!draw != !!read) {198__glXUnlock();199__glXSendError(dpy, BadMatch, None, opcode, True);200return False;201}202203if (oldGC != &dummyContext) {204if (--oldGC->thread_refcount == 0) {205oldGC->vtable->unbind(oldGC, gc);206oldGC->currentDpy = 0;207}208}209210if (gc) {211/* Attempt to bind the context. We do this before mucking with212* gc and __glXSetCurrentContext to properly handle our state in213* case of an error.214*215* If an error occurs, set the Null context since we've already216* blown away our old context. The caller is responsible for217* figuring out how to handle setting a valid context.218*/219if (gc->vtable->bind(gc, oldGC, draw, read) != Success) {220__glXSetCurrentContextNull();221__glXUnlock();222__glXSendError(dpy, GLXBadContext, None, opcode, False);223return GL_FALSE;224}225226if (gc->thread_refcount == 0) {227gc->currentDpy = dpy;228gc->currentDrawable = draw;229gc->currentReadable = read;230}231gc->thread_refcount++;232__glXSetCurrentContext(gc);233} else {234__glXSetCurrentContextNull();235}236237if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) {238/* We are switching away from a context that was239* previously destroyed, so we need to free the memory240* for the old handle. */241oldGC->vtable->destroy(oldGC);242}243244__glXUnlock();245246return GL_TRUE;247}248249_GLX_PUBLIC Bool250glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)251{252return MakeContextCurrent(dpy, draw, draw, gc, X_GLXMakeCurrent);253}254255_GLX_PUBLIC Bool256glXMakeContextCurrent(Display *dpy, GLXDrawable d, GLXDrawable r,257GLXContext ctx)258{259return MakeContextCurrent(dpy, d, r, ctx, X_GLXMakeContextCurrent);260}261262_GLX_PUBLIC Bool263glXMakeCurrentReadSGI(Display *dpy, GLXDrawable d, GLXDrawable r,264GLXContext ctx)265{266return MakeContextCurrent(dpy, d, r, ctx, X_GLXvop_MakeCurrentReadSGI);267}268269270