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 #include <pthread.h>
     37 
     38 #include "glxclient.h"
     39 
     40 #include "glapi.h"
     41 
     42 /*
     43 ** We setup some dummy structures here so that the API can be used
     44 ** even if no context is current.
     45 */
     46 
     47 static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
     48 static struct glx_context_vtable dummyVtable;
     49 /*
     50 ** Dummy context used by small commands when there is no current context.
     51 ** All the
     52 ** gl and glx entry points are designed to operate as nop's when using
     53 ** the dummy context structure.
     54 */
     55 struct glx_context dummyContext = {
     56    &dummyBuffer[0],
     57    &dummyBuffer[0],
     58    &dummyBuffer[0],
     59    &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
     60    sizeof(dummyBuffer),
     61    &dummyVtable
     62 };
     63 
     64 /*
     65  * Current context management and locking
     66  */
     67 
     68 _X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
     69 
     70 # if defined( GLX_USE_TLS )
     71 
     72 /**
     73  * Per-thread GLX context pointer.
     74  *
     75  * \c __glXSetCurrentContext is written is such a way that this pointer can
     76  * \b never be \c NULL.  This is important!  Because of this
     77  * \c __glXGetCurrentContext can be implemented as trivial macro.
     78  */
     79 __thread void *__glX_tls_Context __attribute__ ((tls_model("initial-exec")))
     80    = &dummyContext;
     81 
     82 _X_HIDDEN void
     83 __glXSetCurrentContext(struct glx_context * c)
     84 {
     85    __glX_tls_Context = (c != NULL) ? c : &dummyContext;
     86 }
     87 
     88 # else
     89 
     90 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
     91 
     92 /**
     93  * Per-thread data key.
     94  *
     95  * Once \c init_thread_data has been called, the per-thread data key will
     96  * take a value of \c NULL.  As each new thread is created the default
     97  * value, in that thread, will be \c NULL.
     98  */
     99 static pthread_key_t ContextTSD;
    100 
    101 /**
    102  * Initialize the per-thread data key.
    103  *
    104  * This function is called \b exactly once per-process (not per-thread!) to
    105  * initialize the per-thread data key.  This is ideally done using the
    106  * \c pthread_once mechanism.
    107  */
    108 static void
    109 init_thread_data(void)
    110 {
    111    if (pthread_key_create(&ContextTSD, NULL) != 0) {
    112       perror("pthread_key_create");
    113       exit(-1);
    114    }
    115 }
    116 
    117 _X_HIDDEN void
    118 __glXSetCurrentContext(struct glx_context * c)
    119 {
    120    pthread_once(&once_control, init_thread_data);
    121    pthread_setspecific(ContextTSD, c);
    122 }
    123 
    124 _X_HIDDEN struct glx_context *
    125 __glXGetCurrentContext(void)
    126 {
    127    void *v;
    128 
    129    pthread_once(&once_control, init_thread_data);
    130 
    131    v = pthread_getspecific(ContextTSD);
    132    return (v == NULL) ? &dummyContext : (struct glx_context *) v;
    133 }
    134 
    135 # endif /* defined( GLX_USE_TLS ) */
    136 
    137 
    138 _X_HIDDEN void
    139 __glXSetCurrentContextNull(void)
    140 {
    141    __glXSetCurrentContext(&dummyContext);
    142 #if defined(GLX_DIRECT_RENDERING)
    143    _glapi_set_dispatch(NULL);   /* no-op functions */
    144    _glapi_set_context(NULL);
    145 #endif
    146 }
    147 
    148 _GLX_PUBLIC GLXContext
    149 glXGetCurrentContext(void)
    150 {
    151    struct glx_context *cx = __glXGetCurrentContext();
    152 
    153    if (cx == &dummyContext) {
    154       return NULL;
    155    }
    156    else {
    157       return (GLXContext) cx;
    158    }
    159 }
    160 
    161 _GLX_PUBLIC GLXDrawable
    162 glXGetCurrentDrawable(void)
    163 {
    164    struct glx_context *gc = __glXGetCurrentContext();
    165    return gc->currentDrawable;
    166 }
    167 
    168 static void
    169 __glXGenerateError(Display * dpy, XID resource,
    170                    BYTE errorCode, CARD16 minorCode)
    171 {
    172    xError error;
    173 
    174    error.errorCode = errorCode;
    175    error.resourceID = resource;
    176    error.sequenceNumber = dpy->request;
    177    error.type = X_Error;
    178    error.majorCode = __glXSetupForCommand(dpy);
    179    error.minorCode = minorCode;
    180    _XError(dpy, &error);
    181 }
    182 
    183 /**
    184  * Make a particular context current.
    185  *
    186  * \note This is in this file so that it can access dummyContext.
    187  */
    188 static Bool
    189 MakeContextCurrent(Display * dpy, GLXDrawable draw,
    190                    GLXDrawable read, GLXContext gc_user)
    191 {
    192    struct glx_context *gc = (struct glx_context *) gc_user;
    193    struct glx_context *oldGC = __glXGetCurrentContext();
    194 
    195    /* Make sure that the new context has a nonzero ID.  In the request,
    196     * a zero context ID is used only to mean that we bind to no current
    197     * context.
    198     */
    199    if ((gc != NULL) && (gc->xid == None)) {
    200       return GL_FALSE;
    201    }
    202 
    203    _glapi_check_multithread();
    204 
    205    __glXLock();
    206    if (oldGC == gc &&
    207        gc->currentDrawable == draw && gc->currentReadable == read) {
    208       __glXUnlock();
    209       return True;
    210    }
    211 
    212    if (oldGC != &dummyContext) {
    213       if (--oldGC->thread_refcount == 0) {
    214 	 oldGC->vtable->unbind(oldGC, gc);
    215 	 oldGC->currentDpy = 0;
    216       }
    217    }
    218 
    219    if (gc) {
    220       /* Attempt to bind the context.  We do this before mucking with
    221        * gc and __glXSetCurrentContext to properly handle our state in
    222        * case of an error.
    223        *
    224        * If an error occurs, set the Null context since we've already
    225        * blown away our old context.  The caller is responsible for
    226        * figuring out how to handle setting a valid context.
    227        */
    228       if (gc->vtable->bind(gc, oldGC, draw, read) != Success) {
    229          __glXSetCurrentContextNull();
    230          __glXUnlock();
    231          __glXGenerateError(dpy, None, GLXBadContext, X_GLXMakeContextCurrent);
    232          return GL_FALSE;
    233       }
    234 
    235       if (gc->thread_refcount == 0) {
    236          gc->currentDpy = dpy;
    237          gc->currentDrawable = draw;
    238          gc->currentReadable = read;
    239       }
    240       gc->thread_refcount++;
    241       __glXSetCurrentContext(gc);
    242    } else {
    243       __glXSetCurrentContextNull();
    244    }
    245 
    246    if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid == None) {
    247       /* We are switching away from a context that was
    248        * previously destroyed, so we need to free the memory
    249        * for the old handle. */
    250       oldGC->vtable->destroy(oldGC);
    251    }
    252 
    253    __glXUnlock();
    254 
    255    /* The indirect vertex array state must to be initialised after we
    256     * have setup the context, as it needs to query server attributes.
    257     */
    258    if (gc && !gc->isDirect) {
    259       __GLXattribute *state = gc->client_state_private;
    260       if (state && state->array_state == NULL) {
    261          glGetString(GL_EXTENSIONS);
    262          glGetString(GL_VERSION);
    263          __glXInitVertexArrayState(gc);
    264       }
    265    }
    266 
    267    return GL_TRUE;
    268 }
    269 
    270 
    271 _GLX_PUBLIC Bool
    272 glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
    273 {
    274    return MakeContextCurrent(dpy, draw, draw, gc);
    275 }
    276 
    277 _GLX_PUBLIC
    278 GLX_ALIAS(Bool, glXMakeCurrentReadSGI,
    279           (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
    280           (dpy, d, r, ctx), MakeContextCurrent)
    281 
    282 _GLX_PUBLIC
    283 GLX_ALIAS(Bool, glXMakeContextCurrent,
    284           (Display * dpy, GLXDrawable d, GLXDrawable r,
    285            GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent)
    286