Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. _X_EXPORT 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. _X_EXPORT 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.    return GL_TRUE;
  256. }
  257.  
  258.  
  259. _X_EXPORT Bool
  260. glXMakeCurrent(Display * dpy, GLXDrawable draw, GLXContext gc)
  261. {
  262.    return MakeContextCurrent(dpy, draw, draw, gc);
  263. }
  264.  
  265. _X_EXPORT
  266. GLX_ALIAS(Bool, glXMakeCurrentReadSGI,
  267.           (Display * dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
  268.           (dpy, d, r, ctx), MakeContextCurrent)
  269.  
  270. _X_EXPORT
  271. GLX_ALIAS(Bool, glXMakeContextCurrent,
  272.           (Display * dpy, GLXDrawable d, GLXDrawable r,
  273.            GLXContext ctx), (dpy, d, r, ctx), MakeContextCurrent)
  274.