Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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. #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.