Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
  4.  * 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
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  21.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24.  * DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27.  
  28.  
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include "c99_compat.h"
  32. #include "c11/threads.h"
  33.  
  34. #include "egllog.h"
  35. #include "eglcurrent.h"
  36. #include "eglglobals.h"
  37.  
  38.  
  39. /* This should be kept in sync with _eglInitThreadInfo() */
  40. #define _EGL_THREAD_INFO_INITIALIZER \
  41.    { EGL_SUCCESS, { NULL }, 0 }
  42.  
  43. /* a fallback thread info to guarantee that every thread always has one */
  44. static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
  45. static mtx_t _egl_TSDMutex = _MTX_INITIALIZER_NP;
  46. static EGLBoolean _egl_TSDInitialized;
  47. static tss_t _egl_TSD;
  48. static void (*_egl_FreeTSD)(_EGLThreadInfo *);
  49.  
  50. #ifdef GLX_USE_TLS
  51. static __thread const _EGLThreadInfo *_egl_TLS
  52.    __attribute__ ((tls_model("initial-exec")));
  53. #endif
  54.  
  55. static inline void _eglSetTSD(const _EGLThreadInfo *t)
  56. {
  57.    tss_set(_egl_TSD, (void *) t);
  58. #ifdef GLX_USE_TLS
  59.    _egl_TLS = t;
  60. #endif
  61. }
  62.  
  63. static inline _EGLThreadInfo *_eglGetTSD(void)
  64. {
  65. #ifdef GLX_USE_TLS
  66.    return (_EGLThreadInfo *) _egl_TLS;
  67. #else
  68.    return (_EGLThreadInfo *) tss_get(_egl_TSD);
  69. #endif
  70. }
  71.  
  72. static inline void _eglFiniTSD(void)
  73. {
  74.    mtx_lock(&_egl_TSDMutex);
  75.    if (_egl_TSDInitialized) {
  76.       _EGLThreadInfo *t = _eglGetTSD();
  77.  
  78.       _egl_TSDInitialized = EGL_FALSE;
  79.       if (t && _egl_FreeTSD)
  80.          _egl_FreeTSD((void *) t);
  81.       tss_delete(_egl_TSD);
  82.    }
  83.    mtx_unlock(&_egl_TSDMutex);
  84. }
  85.  
  86. static inline EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
  87. {
  88.    if (!_egl_TSDInitialized) {
  89.       mtx_lock(&_egl_TSDMutex);
  90.  
  91.       /* check again after acquiring lock */
  92.       if (!_egl_TSDInitialized) {
  93.          if (tss_create(&_egl_TSD, (void (*)(void *)) dtor) != thrd_success) {
  94.             mtx_unlock(&_egl_TSDMutex);
  95.             return EGL_FALSE;
  96.          }
  97.          _egl_FreeTSD = dtor;
  98.          _eglAddAtExitCall(_eglFiniTSD);
  99.          _egl_TSDInitialized = EGL_TRUE;
  100.       }
  101.  
  102.       mtx_unlock(&_egl_TSDMutex);
  103.    }
  104.  
  105.    return EGL_TRUE;
  106. }
  107.  
  108. static void
  109. _eglInitThreadInfo(_EGLThreadInfo *t)
  110. {
  111.    memset(t, 0, sizeof(*t));
  112.    t->LastError = EGL_SUCCESS;
  113.    /* default, per EGL spec */
  114.    t->CurrentAPIIndex = _eglConvertApiToIndex(EGL_OPENGL_ES_API);
  115. }
  116.  
  117.  
  118. /**
  119.  * Allocate and init a new _EGLThreadInfo object.
  120.  */
  121. static _EGLThreadInfo *
  122. _eglCreateThreadInfo(void)
  123. {
  124.    _EGLThreadInfo *t = calloc(1, sizeof(_EGLThreadInfo));
  125.    if (t)
  126.       _eglInitThreadInfo(t);
  127.    else
  128.       t = &dummy_thread;
  129.    return t;
  130. }
  131.  
  132.  
  133. /**
  134.  * Delete/free a _EGLThreadInfo object.
  135.  */
  136. static void
  137. _eglDestroyThreadInfo(_EGLThreadInfo *t)
  138. {
  139.    if (t != &dummy_thread)
  140.       free(t);
  141. }
  142.  
  143.  
  144. /**
  145.  * Make sure TSD is initialized and return current value.
  146.  */
  147. static inline _EGLThreadInfo *
  148. _eglCheckedGetTSD(void)
  149. {
  150.    if (_eglInitTSD(&_eglDestroyThreadInfo) != EGL_TRUE) {
  151.       _eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
  152.       return NULL;
  153.    }
  154.  
  155.    return _eglGetTSD();
  156. }
  157.  
  158.  
  159. /**
  160.  * Return the calling thread's thread info.
  161.  * If the calling thread nevers calls this function before, or if its thread
  162.  * info was destroyed, a new one is created.  This function never returns NULL.
  163.  * In the case allocation fails, a dummy one is returned.  See also
  164.  * _eglIsCurrentThreadDummy.
  165.  */
  166. _EGLThreadInfo *
  167. _eglGetCurrentThread(void)
  168. {
  169.    _EGLThreadInfo *t = _eglCheckedGetTSD();
  170.    if (!t) {
  171.       t = _eglCreateThreadInfo();
  172.       _eglSetTSD(t);
  173.    }
  174.  
  175.    return t;
  176. }
  177.  
  178.  
  179. /**
  180.  * Destroy the calling thread's thread info.
  181.  */
  182. void
  183. _eglDestroyCurrentThread(void)
  184. {
  185.    _EGLThreadInfo *t = _eglCheckedGetTSD();
  186.    if (t) {
  187.       _eglDestroyThreadInfo(t);
  188.       _eglSetTSD(NULL);
  189.    }
  190. }
  191.  
  192.  
  193. /**
  194.  * Return true if the calling thread's thread info is dummy.
  195.  * A dummy thread info is shared by all threads and should not be modified.
  196.  * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
  197.  * before updating the thread info.
  198.  */
  199. EGLBoolean
  200. _eglIsCurrentThreadDummy(void)
  201. {
  202.    _EGLThreadInfo *t = _eglCheckedGetTSD();
  203.    return (!t || t == &dummy_thread);
  204. }
  205.  
  206.  
  207. /**
  208.  * Return the currently bound context of the given API, or NULL.
  209.  */
  210. _EGLContext *
  211. _eglGetAPIContext(EGLenum api)
  212. {
  213.    _EGLThreadInfo *t = _eglGetCurrentThread();
  214.    return t->CurrentContexts[_eglConvertApiToIndex(api)];
  215. }
  216.  
  217.  
  218. /**
  219.  * Return the currently bound context of the current API, or NULL.
  220.  */
  221. _EGLContext *
  222. _eglGetCurrentContext(void)
  223. {
  224.    _EGLThreadInfo *t = _eglGetCurrentThread();
  225.    return t->CurrentContexts[t->CurrentAPIIndex];
  226. }
  227.  
  228.  
  229. /**
  230.  * Record EGL error code and return EGL_FALSE.
  231.  */
  232. EGLBoolean
  233. _eglError(EGLint errCode, const char *msg)
  234. {
  235.    _EGLThreadInfo *t = _eglGetCurrentThread();
  236.  
  237.    if (t == &dummy_thread)
  238.       return EGL_FALSE;
  239.  
  240.    t->LastError = errCode;
  241.  
  242.    if (errCode != EGL_SUCCESS) {
  243.       const char *s;
  244.  
  245.       switch (errCode) {
  246.       case EGL_BAD_ACCESS:
  247.          s = "EGL_BAD_ACCESS";
  248.          break;
  249.       case EGL_BAD_ALLOC:
  250.          s = "EGL_BAD_ALLOC";
  251.          break;
  252.       case EGL_BAD_ATTRIBUTE:
  253.          s = "EGL_BAD_ATTRIBUTE";
  254.          break;
  255.       case EGL_BAD_CONFIG:
  256.          s = "EGL_BAD_CONFIG";
  257.          break;
  258.       case EGL_BAD_CONTEXT:
  259.          s = "EGL_BAD_CONTEXT";
  260.          break;
  261.       case EGL_BAD_CURRENT_SURFACE:
  262.          s = "EGL_BAD_CURRENT_SURFACE";
  263.          break;
  264.       case EGL_BAD_DISPLAY:
  265.          s = "EGL_BAD_DISPLAY";
  266.          break;
  267.       case EGL_BAD_MATCH:
  268.          s = "EGL_BAD_MATCH";
  269.          break;
  270.       case EGL_BAD_NATIVE_PIXMAP:
  271.          s = "EGL_BAD_NATIVE_PIXMAP";
  272.          break;
  273.       case EGL_BAD_NATIVE_WINDOW:
  274.          s = "EGL_BAD_NATIVE_WINDOW";
  275.          break;
  276.       case EGL_BAD_PARAMETER:
  277.          s = "EGL_BAD_PARAMETER";
  278.          break;
  279.       case EGL_BAD_SURFACE:
  280.          s = "EGL_BAD_SURFACE";
  281.          break;
  282.       case EGL_NOT_INITIALIZED:
  283.          s = "EGL_NOT_INITIALIZED";
  284.          break;
  285.       default:
  286.          s = "other EGL error";
  287.       }
  288.       _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
  289.    }
  290.  
  291.    return EGL_FALSE;
  292. }
  293.