Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25.  
  26. /*
  27.  * This file manages the OpenGL API dispatch layer.
  28.  * The dispatch table (struct _glapi_table) is basically just a list
  29.  * of function pointers.
  30.  * There are functions to set/get the current dispatch table for the
  31.  * current thread and to manage registration/dispatch of dynamically
  32.  * added extension functions.
  33.  *
  34.  * It's intended that this file and the other glapi*.[ch] files are
  35.  * flexible enough to be reused in several places:  XFree86, DRI-
  36.  * based libGL.so, and perhaps the SGI SI.
  37.  *
  38.  * NOTE: There are no dependencies on Mesa in this code.
  39.  *
  40.  * Versions (API changes):
  41.  *   2000/02/23  - original version for Mesa 3.3 and XFree86 4.0
  42.  *   2001/01/16  - added dispatch override feature for Mesa 3.5
  43.  *   2002/06/28  - added _glapi_set_warning_func(), Mesa 4.1.
  44.  *   2002/10/01  - _glapi_get_proc_address() will now generate new entrypoints
  45.  *                 itself (using offset ~0).  _glapi_add_entrypoint() can be
  46.  *                 called afterward and it'll fill in the correct dispatch
  47.  *                 offset.  This allows DRI libGL to avoid probing for DRI
  48.  *                 drivers!  No changes to the public glapi interface.
  49.  */
  50.  
  51. #include "u_current.h"
  52. #include "u_thread.h"
  53.  
  54. #ifndef MAPI_MODE_UTIL
  55.  
  56. #include "table.h"
  57. #include "stub.h"
  58.  
  59. #else
  60.  
  61. extern void init_glapi_relocs_once(void);
  62. extern void (*__glapi_noop_table[])(void);
  63.  
  64. #define table_noop_array __glapi_noop_table
  65. #define stub_init_once() init_glapi_relocs_once()
  66.  
  67. #endif
  68.  
  69. /**
  70.  * \name Current dispatch and current context control variables
  71.  *
  72.  * Depending on whether or not multithreading is support, and the type of
  73.  * support available, several variables are used to store the current context
  74.  * pointer and the current dispatch table pointer.  In the non-threaded case,
  75.  * the variables \c _glapi_Dispatch and \c _glapi_Context are used for this
  76.  * purpose.
  77.  *
  78.  * In the "normal" threaded case, the variables \c _glapi_Dispatch and
  79.  * \c _glapi_Context will be \c NULL if an application is detected as being
  80.  * multithreaded.  Single-threaded applications will use \c _glapi_Dispatch
  81.  * and \c _glapi_Context just like the case without any threading support.
  82.  * When \c _glapi_Dispatch and \c _glapi_Context are \c NULL, the thread state
  83.  * data \c _gl_DispatchTSD and \c ContextTSD are used.  Drivers and the
  84.  * static dispatch functions access these variables via \c _glapi_get_dispatch
  85.  * and \c _glapi_get_context.
  86.  *
  87.  * There is a race condition in setting \c _glapi_Dispatch to \c NULL.  It is
  88.  * possible for the original thread to be setting it at the same instant a new
  89.  * thread, perhaps running on a different processor, is clearing it.  Because
  90.  * of that, \c ThreadSafe, which can only ever be changed to \c GL_TRUE, is
  91.  * used to determine whether or not the application is multithreaded.
  92.  *
  93.  * In the TLS case, the variables \c _glapi_Dispatch and \c _glapi_Context are
  94.  * hardcoded to \c NULL.  Instead the TLS variables \c _glapi_tls_Dispatch and
  95.  * \c _glapi_tls_Context are used.  Having \c _glapi_Dispatch and
  96.  * \c _glapi_Context be hardcoded to \c NULL maintains binary compatability
  97.  * between TLS enabled loaders and non-TLS DRI drivers.
  98.  */
  99. /*@{*/
  100. #if defined(GLX_USE_TLS)
  101.  
  102. __thread struct mapi_table *u_current_table
  103.     __attribute__((tls_model("initial-exec")))
  104.     = (struct mapi_table *) table_noop_array;
  105.  
  106. __thread void *u_current_user
  107.     __attribute__((tls_model("initial-exec")));
  108.  
  109. #else
  110.  
  111. struct mapi_table *u_current_table =
  112.    (struct mapi_table *) table_noop_array;
  113. void *u_current_user;
  114.  
  115. #ifdef THREADS
  116. struct u_tsd u_current_table_tsd;
  117. static struct u_tsd u_current_user_tsd;
  118. static int ThreadSafe;
  119. #endif /* THREADS */
  120.  
  121. #endif /* defined(GLX_USE_TLS) */
  122. /*@}*/
  123.  
  124.  
  125. void
  126. u_current_destroy(void)
  127. {
  128. #if defined(THREADS) && defined(_WIN32)
  129.    u_tsd_destroy(&u_current_table_tsd);
  130.    u_tsd_destroy(&u_current_user_tsd);
  131. #endif
  132. }
  133.  
  134.  
  135. #if defined(THREADS) && !defined(GLX_USE_TLS)
  136.  
  137. static void
  138. u_current_init_tsd(void)
  139. {
  140.    u_tsd_init(&u_current_table_tsd);
  141.    u_tsd_init(&u_current_user_tsd);
  142. }
  143.  
  144. /**
  145.  * Mutex for multithread check.
  146.  */
  147. u_mutex_declare_static(ThreadCheckMutex);
  148.  
  149. /**
  150.  * We should call this periodically from a function such as glXMakeCurrent
  151.  * in order to test if multiple threads are being used.
  152.  */
  153. void
  154. u_current_init(void)
  155. {
  156.    static unsigned long knownID;
  157.    static int firstCall = 1;
  158.  
  159.    if (ThreadSafe)
  160.       return;
  161.  
  162.    u_mutex_lock(ThreadCheckMutex);
  163.    if (firstCall) {
  164.       u_current_init_tsd();
  165.  
  166.       knownID = u_thread_self();
  167.       firstCall = 0;
  168.    }
  169.    else if (knownID != u_thread_self()) {
  170.       ThreadSafe = 1;
  171.       u_current_set(NULL);
  172.       u_current_set_user(NULL);
  173.    }
  174.    u_mutex_unlock(ThreadCheckMutex);
  175. }
  176.  
  177. #else
  178.  
  179. void
  180. u_current_init(void)
  181. {
  182. }
  183.  
  184. #endif
  185.  
  186.  
  187.  
  188. /**
  189.  * Set the current context pointer for this thread.
  190.  * The context pointer is an opaque type which should be cast to
  191.  * void from the real context pointer type.
  192.  */
  193. void
  194. u_current_set_user(const void *ptr)
  195. {
  196.    u_current_init();
  197.  
  198. #if defined(GLX_USE_TLS)
  199.    u_current_user = (void *) ptr;
  200. #elif defined(THREADS)
  201.    u_tsd_set(&u_current_user_tsd, (void *) ptr);
  202.    u_current_user = (ThreadSafe) ? NULL : (void *) ptr;
  203. #else
  204.    u_current_user = (void *) ptr;
  205. #endif
  206. }
  207.  
  208. /**
  209.  * Get the current context pointer for this thread.
  210.  * The context pointer is an opaque type which should be cast from
  211.  * void to the real context pointer type.
  212.  */
  213. void *
  214. u_current_get_user_internal(void)
  215. {
  216. #if defined(GLX_USE_TLS)
  217.    return u_current_user;
  218. #elif defined(THREADS)
  219.    return (ThreadSafe)
  220.       ? u_tsd_get(&u_current_user_tsd)
  221.       : u_current_user;
  222. #else
  223.    return u_current_user;
  224. #endif
  225. }
  226.  
  227. /**
  228.  * Set the global or per-thread dispatch table pointer.
  229.  * If the dispatch parameter is NULL we'll plug in the no-op dispatch
  230.  * table (__glapi_noop_table).
  231.  */
  232. void
  233. u_current_set(const struct mapi_table *tbl)
  234. {
  235.    u_current_init();
  236.  
  237.    stub_init_once();
  238.  
  239.    if (!tbl)
  240.       tbl = (const struct mapi_table *) table_noop_array;
  241.  
  242. #if defined(GLX_USE_TLS)
  243.    u_current_table = (struct mapi_table *) tbl;
  244. #elif defined(THREADS)
  245.    u_tsd_set(&u_current_table_tsd, (void *) tbl);
  246.    u_current_table = (ThreadSafe) ? NULL : (void *) tbl;
  247. #else
  248.    u_current_table = (struct mapi_table *) tbl;
  249. #endif
  250. }
  251.  
  252. /**
  253.  * Return pointer to current dispatch table for calling thread.
  254.  */
  255. struct mapi_table *
  256. u_current_get_internal(void)
  257. {
  258. #if defined(GLX_USE_TLS)
  259.    return u_current_table;
  260. #elif defined(THREADS)
  261.    return (struct mapi_table *) ((ThreadSafe) ?
  262.          u_tsd_get(&u_current_table_tsd) : (void *) u_current_table);
  263. #else
  264.    return u_current_table;
  265. #endif
  266. }
  267.