Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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 "egllog.h"
  32. #include "eglmutex.h"
  33. #include "eglcurrent.h"
  34. #include "eglglobals.h"
  35.  
  36.  
  37. /* This should be kept in sync with _eglInitThreadInfo() */
  38. #define _EGL_THREAD_INFO_INITIALIZER \
  39.    { EGL_SUCCESS, { NULL }, 0 }
  40.  
  41. /* a fallback thread info to guarantee that every thread always has one */
  42. static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
  43.  
  44.  
  45. #if HAVE_PTHREAD
  46. #include <pthread.h>
  47.  
  48. static _EGL_DECLARE_MUTEX(_egl_TSDMutex);
  49. static EGLBoolean _egl_TSDInitialized;
  50. static pthread_key_t _egl_TSD;
  51. static void (*_egl_FreeTSD)(_EGLThreadInfo *);
  52.  
  53. #ifdef GLX_USE_TLS
  54. static __thread const _EGLThreadInfo *_egl_TLS
  55.    __attribute__ ((tls_model("initial-exec")));
  56. #endif
  57.  
  58. static INLINE void _eglSetTSD(const _EGLThreadInfo *t)
  59. {
  60.    pthread_setspecific(_egl_TSD, (const void *) t);
  61. #ifdef GLX_USE_TLS
  62.    _egl_TLS = t;
  63. #endif
  64. }
  65.  
  66. static INLINE _EGLThreadInfo *_eglGetTSD(void)
  67. {
  68. #ifdef GLX_USE_TLS
  69.    return (_EGLThreadInfo *) _egl_TLS;
  70. #else
  71.    return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD);
  72. #endif
  73. }
  74.  
  75. static INLINE void _eglFiniTSD(void)
  76. {
  77.    _eglLockMutex(&_egl_TSDMutex);
  78.    if (_egl_TSDInitialized) {
  79.       _EGLThreadInfo *t = _eglGetTSD();
  80.  
  81.       _egl_TSDInitialized = EGL_FALSE;
  82.       if (t && _egl_FreeTSD)
  83.          _egl_FreeTSD((void *) t);
  84.       pthread_key_delete(_egl_TSD);
  85.    }
  86.    _eglUnlockMutex(&_egl_TSDMutex);
  87. }
  88.  
  89. static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
  90. {
  91.    if (!_egl_TSDInitialized) {
  92.       _eglLockMutex(&_egl_TSDMutex);
  93.  
  94.       /* check again after acquiring lock */
  95.       if (!_egl_TSDInitialized) {
  96.          if (pthread_key_create(&_egl_TSD, (void (*)(void *)) dtor) != 0) {
  97.             _eglUnlockMutex(&_egl_TSDMutex);
  98.             return EGL_FALSE;
  99.          }
  100.          _egl_FreeTSD = dtor;
  101.          _eglAddAtExitCall(_eglFiniTSD);
  102.          _egl_TSDInitialized = EGL_TRUE;
  103.       }
  104.  
  105.       _eglUnlockMutex(&_egl_TSDMutex);
  106.    }
  107.  
  108.    return EGL_TRUE;
  109. }
  110.  
  111. #else /* HAVE_PTHREAD */
  112. static const _EGLThreadInfo *_egl_TSD;
  113. static void (*_egl_FreeTSD)(_EGLThreadInfo *);
  114.  
  115. static INLINE void _eglSetTSD(const _EGLThreadInfo *t)
  116. {
  117.    _egl_TSD = t;
  118. }
  119.  
  120. static INLINE _EGLThreadInfo *_eglGetTSD(void)
  121. {
  122.    return (_EGLThreadInfo *) _egl_TSD;
  123. }
  124.  
  125. static INLINE void _eglFiniTSD(void)
  126. {
  127.    if (_egl_FreeTSD && _egl_TSD)
  128.       _egl_FreeTSD((_EGLThreadInfo *) _egl_TSD);
  129. }
  130.  
  131. static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
  132. {
  133.    if (!_egl_FreeTSD && dtor) {
  134.       _egl_FreeTSD = dtor;
  135.       _eglAddAtExitCall(_eglFiniTSD);
  136.    }
  137.    return EGL_TRUE;
  138. }
  139.  
  140. #endif /* !HAVE_PTHREAD */
  141.  
  142.  
  143. static void
  144. _eglInitThreadInfo(_EGLThreadInfo *t)
  145. {
  146.    memset(t, 0, sizeof(*t));
  147.    t->LastError = EGL_SUCCESS;
  148.    /* default, per EGL spec */
  149.    t->CurrentAPIIndex = _eglConvertApiToIndex(EGL_OPENGL_ES_API);
  150. }
  151.  
  152.  
  153. /**
  154.  * Allocate and init a new _EGLThreadInfo object.
  155.  */
  156. static _EGLThreadInfo *
  157. _eglCreateThreadInfo(void)
  158. {
  159.    _EGLThreadInfo *t = calloc(1, sizeof(_EGLThreadInfo));
  160.    if (t)
  161.       _eglInitThreadInfo(t);
  162.    else
  163.       t = &dummy_thread;
  164.    return t;
  165. }
  166.  
  167.  
  168. /**
  169.  * Delete/free a _EGLThreadInfo object.
  170.  */
  171. static void
  172. _eglDestroyThreadInfo(_EGLThreadInfo *t)
  173. {
  174.    if (t != &dummy_thread)
  175.       free(t);
  176. }
  177.  
  178.  
  179. /**
  180.  * Make sure TSD is initialized and return current value.
  181.  */
  182. static INLINE _EGLThreadInfo *
  183. _eglCheckedGetTSD(void)
  184. {
  185.    if (_eglInitTSD(&_eglDestroyThreadInfo) != EGL_TRUE) {
  186.       _eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
  187.       return NULL;
  188.    }
  189.  
  190.    return _eglGetTSD();
  191. }
  192.  
  193.  
  194. /**
  195.  * Return the calling thread's thread info.
  196.  * If the calling thread nevers calls this function before, or if its thread
  197.  * info was destroyed, a new one is created.  This function never returns NULL.
  198.  * In the case allocation fails, a dummy one is returned.  See also
  199.  * _eglIsCurrentThreadDummy.
  200.  */
  201. _EGLThreadInfo *
  202. _eglGetCurrentThread(void)
  203. {
  204.    _EGLThreadInfo *t = _eglCheckedGetTSD();
  205.    if (!t) {
  206.       t = _eglCreateThreadInfo();
  207.       _eglSetTSD(t);
  208.    }
  209.  
  210.    return t;
  211. }
  212.  
  213.  
  214. /**
  215.  * Destroy the calling thread's thread info.
  216.  */
  217. void
  218. _eglDestroyCurrentThread(void)
  219. {
  220.    _EGLThreadInfo *t = _eglCheckedGetTSD();
  221.    if (t) {
  222.       _eglDestroyThreadInfo(t);
  223.       _eglSetTSD(NULL);
  224.    }
  225. }
  226.  
  227.  
  228. /**
  229.  * Return true if the calling thread's thread info is dummy.
  230.  * A dummy thread info is shared by all threads and should not be modified.
  231.  * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
  232.  * before updating the thread info.
  233.  */
  234. EGLBoolean
  235. _eglIsCurrentThreadDummy(void)
  236. {
  237.    _EGLThreadInfo *t = _eglCheckedGetTSD();
  238.    return (!t || t == &dummy_thread);
  239. }
  240.  
  241.  
  242. /**
  243.  * Return the currently bound context of the given API, or NULL.
  244.  */
  245. PUBLIC _EGLContext *
  246. _eglGetAPIContext(EGLenum api)
  247. {
  248.    _EGLThreadInfo *t = _eglGetCurrentThread();
  249.    return t->CurrentContexts[_eglConvertApiToIndex(api)];
  250. }
  251.  
  252.  
  253. /**
  254.  * Return the currently bound context of the current API, or NULL.
  255.  */
  256. _EGLContext *
  257. _eglGetCurrentContext(void)
  258. {
  259.    _EGLThreadInfo *t = _eglGetCurrentThread();
  260.    return t->CurrentContexts[t->CurrentAPIIndex];
  261. }
  262.  
  263.  
  264. /**
  265.  * Record EGL error code and return EGL_FALSE.
  266.  */
  267. EGLBoolean
  268. _eglError(EGLint errCode, const char *msg)
  269. {
  270.    _EGLThreadInfo *t = _eglGetCurrentThread();
  271.  
  272.    if (t == &dummy_thread)
  273.       return EGL_FALSE;
  274.  
  275.    t->LastError = errCode;
  276.  
  277.    if (errCode != EGL_SUCCESS) {
  278.       const char *s;
  279.  
  280.       switch (errCode) {
  281.       case EGL_BAD_ACCESS:
  282.          s = "EGL_BAD_ACCESS";
  283.          break;
  284.       case EGL_BAD_ALLOC:
  285.          s = "EGL_BAD_ALLOC";
  286.          break;
  287.       case EGL_BAD_ATTRIBUTE:
  288.          s = "EGL_BAD_ATTRIBUTE";
  289.          break;
  290.       case EGL_BAD_CONFIG:
  291.          s = "EGL_BAD_CONFIG";
  292.          break;
  293.       case EGL_BAD_CONTEXT:
  294.          s = "EGL_BAD_CONTEXT";
  295.          break;
  296.       case EGL_BAD_CURRENT_SURFACE:
  297.          s = "EGL_BAD_CURRENT_SURFACE";
  298.          break;
  299.       case EGL_BAD_DISPLAY:
  300.          s = "EGL_BAD_DISPLAY";
  301.          break;
  302.       case EGL_BAD_MATCH:
  303.          s = "EGL_BAD_MATCH";
  304.          break;
  305.       case EGL_BAD_NATIVE_PIXMAP:
  306.          s = "EGL_BAD_NATIVE_PIXMAP";
  307.          break;
  308.       case EGL_BAD_NATIVE_WINDOW:
  309.          s = "EGL_BAD_NATIVE_WINDOW";
  310.          break;
  311.       case EGL_BAD_PARAMETER:
  312.          s = "EGL_BAD_PARAMETER";
  313.          break;
  314.       case EGL_BAD_SURFACE:
  315.          s = "EGL_BAD_SURFACE";
  316.          break;
  317.       case EGL_NOT_INITIALIZED:
  318.          s = "EGL_NOT_INITIALIZED";
  319.          break;
  320. #ifdef EGL_MESA_screen_surface
  321.       case EGL_BAD_SCREEN_MESA:
  322.          s = "EGL_BAD_SCREEN_MESA";
  323.          break;
  324.       case EGL_BAD_MODE_MESA:
  325.          s = "EGL_BAD_MODE_MESA";
  326.          break;
  327. #endif
  328.       default:
  329.          s = "other EGL error";
  330.       }
  331.       _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
  332.    }
  333.  
  334.    return EGL_FALSE;
  335. }
  336.