Home | History | Annotate | Download | only in glx
      1 /*
      2  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
      3  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice including the dates of first publication and
     13  * either this permission notice or a reference to
     14  * http://oss.sgi.com/projects/FreeB/
     15  * shall be included in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     22  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24  *
     25  * Except as contained in this notice, the name of Silicon Graphics, Inc.
     26  * shall not be used in advertising or otherwise to promote the sale, use or
     27  * other dealings in this Software without prior written authorization from
     28  * Silicon Graphics, Inc.
     29  */
     30 
     31 /**
     32  * \file glxcurrent.c
     33  * Client-side GLX interface for current context management.
     34  */
     35 
     36 #ifdef HAVE_PTHREAD
     37 #include <pthread.h>
     38 #endif
     39 
     40 #include "glxclient.h"
     41 #ifdef GLX_USE_APPLEGL
     42 #include <stdlib.h>
     43 
     44 #include "apple_glx.h"
     45 #include "apple_glx_context.h"
     46 #endif
     47 
     48 #include "glapi.h"
     49 
     50 /*
     51 ** We setup some dummy structures here so that the API can be used
     52 ** even if no context is current.
     53 */
     54 
     55 static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
     56 static struct glx_context_vtable dummyVtable;
     57 /*
     58 ** Dummy context used by small commands when there is no current context.
     59 ** All the
     60 ** gl and glx entry points are designed to operate as nop's when using
     61 ** the dummy context structure.
     62 */
     63 struct glx_context dummyContext = {
     64    &dummyBuffer[0],
     65    &dummyBuffer[0],
     66    &dummyBuffer[0],
     67    &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
     68    sizeof(dummyBuffer),
     69    &dummyVtable
     70 };
     71 
     72 /*
     73  * Current context management and locking
     74  */
     75 
     76 #if defined( HAVE_PTHREAD )
     77 
     78 _X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
     79 
     80 # if defined( GLX_USE_TLS )
     81 
     82 /**
     83  * Per-thread GLX context pointer.
     84  *
     85  * \c __glXSetCurrentContext is written is such a way that this pointer can
     86  * \b never be \c NULL.  This is important!  Because of this
     87  * \c __glXGetCurrentContext can be implemented as trivial macro.
     88  */
     89 __thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec")))
     90    = &dummyContext;
     91 
     92 _X_HIDDEN void
     93 __glXSetCurrentContext(struct glx_context * c)
     94 {
     95    __glX_tls_Context = (c != NULL) ? c : &dummyContext;
     96 }
     97 
     98 # else
     99 
    100 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
    101 
    102 /**
    103  * Per-thread data key.
    104  *
    105  * Once \c init_thread_data has been called, the per-thread data key will
    106  * take a value of \c NULL.  As each new thread is created the default
    107  * value, in that thread, will be \c NULL.
    108  */
    109 static pthread_key_t ContextTSD;
    110 
    111 /**
    112  * Initialize the per-thread data key.
    113  *
    114  * This function is called \b exactly once per-process (not per-thread!) to
    115  * initialize the per-thread data key.  This is ideally done using the
    116  * \c pthread_once mechanism.
    117  */
    118 static void
    119 init_thread_data(void)
    120 {
    121    if (pthread_key_create(&ContextTSD, NULL) != 0) {
    122       perror("pthread_key_create");
    123       exit(-1);
    124    }
    125 }
    126 
    127 _X_HIDDEN void
    128 __glXSetCurrentContext(struct glx_context * c)
    129 {
    130    pthread_once(&once_control, init_thread_data);
    131    pthread_setspecific(ContextTSD, c);
    132 }
    133 
    134 _X_HIDDEN struct glx_context *
    135 __glXGetCurrentContext(void)
    136 {
    137    void *v;
    138 
    139    pthread_once(&once_control, init_thread_data);
    140 
    141    v = pthread_getspecific(ContextTSD);
    142    return (v == NULL) ? &dummyContext : (struct glx_context *) v;
    143 }
    144 
    145 # endif /* defined( GLX_USE_TLS ) */
    146 
    147 #elif defined( THREADS )
    148 
    149 #error Unknown threading method specified.
    150 
    151 #else
    152 
    153 /* not thread safe */
    154 _X_HIDDEN struct glx_context *__glXcurrentContext = &dummyContext;
    155 
    156 #endif
    157 
    158 
    159 _X_HIDDEN void
    160 __glXSetCurrentContextNull(void)
    161 {
    162    __glXSetCurrentContext(&dummyContext);
    163 #if defined(GLX_DIRECT_RENDERING)
    164    _glapi_set_dispatch(NULL);   /* no-op functions */
    165    _glapi_set_context(NULL);
    166 #endif
    167 }
    168 
    169 _X_EXPORT GLXContext
    170 glXGetCurrentContext(void)
    171 {
    172    struct glx_context *cx = __glXGetCurrentContext();
    173 
    174    if (cx == &dummyContext) {
    175       return NULL;
    176    }
    177    else {
    178       return (GLXContext) cx;
    179    }
    180 }
    181 
    182 _X_EXPORT GLXDrawable
    183 glXGetCurrentDrawable(void)
    184 {
    185    struct glx_context *gc = __glXGetCurrentContext();
    186    return gc->currentDrawable;
    187 }
    188 
    189 static void
    190 __glXGenerateError(Display * dpy, XID resource,
    191                    BYTE errorCode, CARD16 minorCode)
    192 {
    193    xError error;
    194 
    195    error.errorCode = errorCode;
    196    error.resourceID = resource;
    197    error.sequenceNumber = dpy->request;
    198    error.type = X_Error;
    199    error.majorCode = __glXSetupForCommand(dpy);
    200    error.minorCode = minorCode;
    201    _XError(dpy, &error);
    202 }
    203 
    204 /**
    205  * Make a particular context current.
    206  *
    207  * \note This is in this file so that it can access dummyContext.
    208  */
    209 static Bool
    210 MakeContextCurrent(Display * dpy, GLXDrawable draw,
    211                    GLXDrawable read, GLXContext gc_user)
    212 {
    213    struct glx_context *gc = (struct glx_context *) gc_user;
    214    struct glx_context *oldGC = __glXGetCurrentContext();
    215 
    216    /* XXX: If this is left out, then libGL ends up not having this
    217     * symbol, and drivers using it fail to load.  Compare the
    218     * implementation of this symbol to _glapi_noop_enable_warnings(),
    219     * though, which gets into the library despite no callers, the same
    220     * prototypes, and the same compile flags to the files containing
    221     * them.  Moving the definition to glapi_nop.c gets it into the
    222     * library, though.
    223     */
    224    (void)_glthread_GetID();
    225 
    226    /* Make sure that the new context has a nonzero ID.  In the request,
    227     * a zero context ID is used only to mean that we bind to no current
    228     * context.
    229     */
    230    if ((gc != NULL) && (gc->xid == None)) {
    231       return GL_FALSE;
    232    }
    233 
    234    if (gc == NULL && (draw != None || read != None)) {
    235       __glXGenerateError(dpy, (draw != None) ? draw : read,
    236                          BadMatch, X_GLXMakeContextCurrent);
    237       return False;
    238    }
    239    if (gc != NULL && (draw == None || read == None)) {
    240       __glXGenerateError(dpy, None, BadMatch, X_GLXMakeContextCurrent);
    241       return False;
    242    }
    243 
    244    _glapi_check_multithread();
    245 
    246    __glXLock();
    247    if (oldGC == gc &&
    248        gc->currentDrawable == draw && gc->currentReadable == read) {
    249       __glXUnlock();
    250       return True;
    251    }
    252 
    253    if (oldGC != &dummyContext) {
    254       if (--oldGC->thread_refcount == 0) {
    255 	 oldGC->vtable->unbind(oldGC, gc);
    256 	 oldGC->currentDpy = 0;
    257       }
    258    }
    259 
    260    if (gc) {
    261       /* Attempt to bind the context.  We do this before mucking with
    262        * gc and __glXSetCurrentContext to properly handle our state in
    263        * case of an error.
    264        *
    265        * If an error occurs, set the Null context since we've already
    266        * blown away our old context.  The caller is responsible for
    267        * figuring out how to handle setting a valid context.
    268        */
    269       if (gc->vtable->bind(gc, oldGC, draw, read) != Success) {
    270          __glXSetCurrentContextNull();
    271          __glXUnlock();
    272          __glXGenerateError(dpy, None, GLXBadContext, X_GLXMakeContextCurrent);
    273          return GL_FALSE;
    274       }
    275 
    276       if (gc->thread_refcount == 0) {
    277          gc->currentDpy = dpy;
    278          gc->currentDrawable = draw;
    279          gc->currentReadable = read;
    280       }
    281       gc->thread_refcount++;
    282       __glXSetCurrentContext(gc);
    283    } else {
    284       __glXSetCurrentContextNull();
    285    }
    286 
    287    if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) {
    288       /* We are switching away from a context that was
    289        * previously destroyed, so we need to free the memory
    290        * for the old handle. */
    291       oldGC->vtable->destroy(oldGC);
    292    }
    293 
    294    __glXUnlock();
    295 
    296    return GL_TRUE;
    297 }
    298 
    299 
    300 _X_EXPORT Bool
    301 glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
    302 {
    303    return MakeContextCurrent(dpy, draw, draw, gc);
    304 }
    305 
    306 _X_EXPORT
    307 GLX_ALIAS(Bool, glXMakeCurrentReadSGI,
    308           (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
    309           (dpy, d, r, ctx), MakeContextCurrent)
    310 
    311 _X_EXPORT
    312 GLX_ALIAS(Bool, glXMakeContextCurrent,
    313           (Display * dpy, GLXDrawable d, GLXDrawable r,
    314            GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent)
    315