eglcurrent.c revision af69d88d
13464ebd5Sriastradh/**************************************************************************
23464ebd5Sriastradh *
33464ebd5Sriastradh * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
43464ebd5Sriastradh * All Rights Reserved.
53464ebd5Sriastradh *
63464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
73464ebd5Sriastradh * copy of this software and associated documentation files (the
83464ebd5Sriastradh * "Software"), to deal in the Software without restriction, including
93464ebd5Sriastradh * without limitation the rights to use, copy, modify, merge, publish,
103464ebd5Sriastradh * distribute, sub license, and/or sell copies of the Software, and to
113464ebd5Sriastradh * permit persons to whom the Software is furnished to do so, subject to
123464ebd5Sriastradh * the following conditions:
133464ebd5Sriastradh *
143464ebd5Sriastradh * The above copyright notice and this permission notice (including the
153464ebd5Sriastradh * next paragraph) shall be included in all copies or substantial portions
163464ebd5Sriastradh * of the Software.
173464ebd5Sriastradh *
183464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
193464ebd5Sriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
203464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
213464ebd5Sriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
223464ebd5Sriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
233464ebd5Sriastradh * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
243464ebd5Sriastradh * DEALINGS IN THE SOFTWARE.
253464ebd5Sriastradh *
263464ebd5Sriastradh **************************************************************************/
273464ebd5Sriastradh
283464ebd5Sriastradh
294a49301eSmrg#include <stdlib.h>
304a49301eSmrg#include <string.h>
314a49301eSmrg#include "egllog.h"
324a49301eSmrg#include "eglmutex.h"
33cdc920a0Smrg#include "eglcurrent.h"
343464ebd5Sriastradh#include "eglglobals.h"
354a49301eSmrg
364a49301eSmrg
374a49301eSmrg/* This should be kept in sync with _eglInitThreadInfo() */
384a49301eSmrg#define _EGL_THREAD_INFO_INITIALIZER \
394a49301eSmrg   { EGL_SUCCESS, { NULL }, 0 }
404a49301eSmrg
414a49301eSmrg/* a fallback thread info to guarantee that every thread always has one */
424a49301eSmrgstatic _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
434a49301eSmrg
444a49301eSmrg
45af69d88dSmrg#if HAVE_PTHREAD
464a49301eSmrg#include <pthread.h>
474a49301eSmrg
48af69d88dSmrgstatic _EGLMutex _egl_TSDMutex = _EGL_MUTEX_INITIALIZER;
494a49301eSmrgstatic EGLBoolean _egl_TSDInitialized;
504a49301eSmrgstatic pthread_key_t _egl_TSD;
514a49301eSmrgstatic void (*_egl_FreeTSD)(_EGLThreadInfo *);
524a49301eSmrg
533464ebd5Sriastradh#ifdef GLX_USE_TLS
543464ebd5Sriastradhstatic __thread const _EGLThreadInfo *_egl_TLS
553464ebd5Sriastradh   __attribute__ ((tls_model("initial-exec")));
563464ebd5Sriastradh#endif
573464ebd5Sriastradh
584a49301eSmrgstatic INLINE void _eglSetTSD(const _EGLThreadInfo *t)
594a49301eSmrg{
604a49301eSmrg   pthread_setspecific(_egl_TSD, (const void *) t);
613464ebd5Sriastradh#ifdef GLX_USE_TLS
623464ebd5Sriastradh   _egl_TLS = t;
633464ebd5Sriastradh#endif
644a49301eSmrg}
654a49301eSmrg
664a49301eSmrgstatic INLINE _EGLThreadInfo *_eglGetTSD(void)
674a49301eSmrg{
683464ebd5Sriastradh#ifdef GLX_USE_TLS
693464ebd5Sriastradh   return (_EGLThreadInfo *) _egl_TLS;
703464ebd5Sriastradh#else
714a49301eSmrg   return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD);
723464ebd5Sriastradh#endif
734a49301eSmrg}
744a49301eSmrg
754a49301eSmrgstatic INLINE void _eglFiniTSD(void)
764a49301eSmrg{
774a49301eSmrg   _eglLockMutex(&_egl_TSDMutex);
784a49301eSmrg   if (_egl_TSDInitialized) {
794a49301eSmrg      _EGLThreadInfo *t = _eglGetTSD();
804a49301eSmrg
814a49301eSmrg      _egl_TSDInitialized = EGL_FALSE;
824a49301eSmrg      if (t && _egl_FreeTSD)
834a49301eSmrg         _egl_FreeTSD((void *) t);
844a49301eSmrg      pthread_key_delete(_egl_TSD);
854a49301eSmrg   }
864a49301eSmrg   _eglUnlockMutex(&_egl_TSDMutex);
874a49301eSmrg}
884a49301eSmrg
894a49301eSmrgstatic INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
904a49301eSmrg{
914a49301eSmrg   if (!_egl_TSDInitialized) {
924a49301eSmrg      _eglLockMutex(&_egl_TSDMutex);
934a49301eSmrg
944a49301eSmrg      /* check again after acquiring lock */
954a49301eSmrg      if (!_egl_TSDInitialized) {
964a49301eSmrg         if (pthread_key_create(&_egl_TSD, (void (*)(void *)) dtor) != 0) {
974a49301eSmrg            _eglUnlockMutex(&_egl_TSDMutex);
984a49301eSmrg            return EGL_FALSE;
994a49301eSmrg         }
1004a49301eSmrg         _egl_FreeTSD = dtor;
1014a49301eSmrg         _eglAddAtExitCall(_eglFiniTSD);
1024a49301eSmrg         _egl_TSDInitialized = EGL_TRUE;
1034a49301eSmrg      }
1044a49301eSmrg
1054a49301eSmrg      _eglUnlockMutex(&_egl_TSDMutex);
1064a49301eSmrg   }
1074a49301eSmrg
1084a49301eSmrg   return EGL_TRUE;
1094a49301eSmrg}
1104a49301eSmrg
111af69d88dSmrg#else /* HAVE_PTHREAD */
1124a49301eSmrgstatic const _EGLThreadInfo *_egl_TSD;
1134a49301eSmrgstatic void (*_egl_FreeTSD)(_EGLThreadInfo *);
1144a49301eSmrg
1154a49301eSmrgstatic INLINE void _eglSetTSD(const _EGLThreadInfo *t)
1164a49301eSmrg{
1174a49301eSmrg   _egl_TSD = t;
1184a49301eSmrg}
1194a49301eSmrg
1204a49301eSmrgstatic INLINE _EGLThreadInfo *_eglGetTSD(void)
1214a49301eSmrg{
1224a49301eSmrg   return (_EGLThreadInfo *) _egl_TSD;
1234a49301eSmrg}
1244a49301eSmrg
1254a49301eSmrgstatic INLINE void _eglFiniTSD(void)
1264a49301eSmrg{
1274a49301eSmrg   if (_egl_FreeTSD && _egl_TSD)
1284a49301eSmrg      _egl_FreeTSD((_EGLThreadInfo *) _egl_TSD);
1294a49301eSmrg}
1304a49301eSmrg
1314a49301eSmrgstatic INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
1324a49301eSmrg{
1334a49301eSmrg   if (!_egl_FreeTSD && dtor) {
1344a49301eSmrg      _egl_FreeTSD = dtor;
1354a49301eSmrg      _eglAddAtExitCall(_eglFiniTSD);
1364a49301eSmrg   }
1374a49301eSmrg   return EGL_TRUE;
1384a49301eSmrg}
1394a49301eSmrg
140af69d88dSmrg#endif /* !HAVE_PTHREAD */
1414a49301eSmrg
1424a49301eSmrg
1434a49301eSmrgstatic void
1444a49301eSmrg_eglInitThreadInfo(_EGLThreadInfo *t)
1454a49301eSmrg{
1464a49301eSmrg   memset(t, 0, sizeof(*t));
1474a49301eSmrg   t->LastError = EGL_SUCCESS;
1484a49301eSmrg   /* default, per EGL spec */
1494a49301eSmrg   t->CurrentAPIIndex = _eglConvertApiToIndex(EGL_OPENGL_ES_API);
1504a49301eSmrg}
1514a49301eSmrg
1524a49301eSmrg
1534a49301eSmrg/**
1544a49301eSmrg * Allocate and init a new _EGLThreadInfo object.
1554a49301eSmrg */
1564a49301eSmrgstatic _EGLThreadInfo *
1574a49301eSmrg_eglCreateThreadInfo(void)
1584a49301eSmrg{
159af69d88dSmrg   _EGLThreadInfo *t = calloc(1, sizeof(_EGLThreadInfo));
1604a49301eSmrg   if (t)
1614a49301eSmrg      _eglInitThreadInfo(t);
1624a49301eSmrg   else
1634a49301eSmrg      t = &dummy_thread;
1644a49301eSmrg   return t;
1654a49301eSmrg}
1664a49301eSmrg
1674a49301eSmrg
1684a49301eSmrg/**
1694a49301eSmrg * Delete/free a _EGLThreadInfo object.
1704a49301eSmrg */
1714a49301eSmrgstatic void
1724a49301eSmrg_eglDestroyThreadInfo(_EGLThreadInfo *t)
1734a49301eSmrg{
1744a49301eSmrg   if (t != &dummy_thread)
1754a49301eSmrg      free(t);
1764a49301eSmrg}
1774a49301eSmrg
1784a49301eSmrg
1794a49301eSmrg/**
1804a49301eSmrg * Make sure TSD is initialized and return current value.
1814a49301eSmrg */
1824a49301eSmrgstatic INLINE _EGLThreadInfo *
1834a49301eSmrg_eglCheckedGetTSD(void)
1844a49301eSmrg{
1854a49301eSmrg   if (_eglInitTSD(&_eglDestroyThreadInfo) != EGL_TRUE) {
1864a49301eSmrg      _eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
1874a49301eSmrg      return NULL;
1884a49301eSmrg   }
1894a49301eSmrg
1904a49301eSmrg   return _eglGetTSD();
1914a49301eSmrg}
1924a49301eSmrg
1934a49301eSmrg
1944a49301eSmrg/**
1954a49301eSmrg * Return the calling thread's thread info.
1964a49301eSmrg * If the calling thread nevers calls this function before, or if its thread
1974a49301eSmrg * info was destroyed, a new one is created.  This function never returns NULL.
1984a49301eSmrg * In the case allocation fails, a dummy one is returned.  See also
1994a49301eSmrg * _eglIsCurrentThreadDummy.
2004a49301eSmrg */
2014a49301eSmrg_EGLThreadInfo *
2024a49301eSmrg_eglGetCurrentThread(void)
2034a49301eSmrg{
2044a49301eSmrg   _EGLThreadInfo *t = _eglCheckedGetTSD();
2054a49301eSmrg   if (!t) {
2064a49301eSmrg      t = _eglCreateThreadInfo();
2074a49301eSmrg      _eglSetTSD(t);
2084a49301eSmrg   }
2094a49301eSmrg
2104a49301eSmrg   return t;
2114a49301eSmrg}
2124a49301eSmrg
2134a49301eSmrg
2144a49301eSmrg/**
2154a49301eSmrg * Destroy the calling thread's thread info.
2164a49301eSmrg */
2174a49301eSmrgvoid
2184a49301eSmrg_eglDestroyCurrentThread(void)
2194a49301eSmrg{
2204a49301eSmrg   _EGLThreadInfo *t = _eglCheckedGetTSD();
2214a49301eSmrg   if (t) {
2224a49301eSmrg      _eglDestroyThreadInfo(t);
2234a49301eSmrg      _eglSetTSD(NULL);
2244a49301eSmrg   }
2254a49301eSmrg}
2264a49301eSmrg
2274a49301eSmrg
2284a49301eSmrg/**
2294a49301eSmrg * Return true if the calling thread's thread info is dummy.
2304a49301eSmrg * A dummy thread info is shared by all threads and should not be modified.
2314a49301eSmrg * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
2324a49301eSmrg * before updating the thread info.
2334a49301eSmrg */
2344a49301eSmrgEGLBoolean
2354a49301eSmrg_eglIsCurrentThreadDummy(void)
2364a49301eSmrg{
2374a49301eSmrg   _EGLThreadInfo *t = _eglCheckedGetTSD();
2384a49301eSmrg   return (!t || t == &dummy_thread);
2394a49301eSmrg}
2404a49301eSmrg
2414a49301eSmrg
2424a49301eSmrg/**
243cdc920a0Smrg * Return the currently bound context of the given API, or NULL.
2444a49301eSmrg */
245cdc920a0SmrgPUBLIC _EGLContext *
246cdc920a0Smrg_eglGetAPIContext(EGLenum api)
2474a49301eSmrg{
2484a49301eSmrg   _EGLThreadInfo *t = _eglGetCurrentThread();
249cdc920a0Smrg   return t->CurrentContexts[_eglConvertApiToIndex(api)];
2504a49301eSmrg}
2514a49301eSmrg
2524a49301eSmrg
2534a49301eSmrg/**
254cdc920a0Smrg * Return the currently bound context of the current API, or NULL.
2554a49301eSmrg */
256cdc920a0Smrg_EGLContext *
257cdc920a0Smrg_eglGetCurrentContext(void)
2584a49301eSmrg{
2594a49301eSmrg   _EGLThreadInfo *t = _eglGetCurrentThread();
260cdc920a0Smrg   return t->CurrentContexts[t->CurrentAPIIndex];
2614a49301eSmrg}
2624a49301eSmrg
2634a49301eSmrg
2644a49301eSmrg/**
265cdc920a0Smrg * Record EGL error code and return EGL_FALSE.
2664a49301eSmrg */
2674a49301eSmrgEGLBoolean
2684a49301eSmrg_eglError(EGLint errCode, const char *msg)
2694a49301eSmrg{
2704a49301eSmrg   _EGLThreadInfo *t = _eglGetCurrentThread();
2714a49301eSmrg
2724a49301eSmrg   if (t == &dummy_thread)
2734a49301eSmrg      return EGL_FALSE;
2744a49301eSmrg
275cdc920a0Smrg   t->LastError = errCode;
276cdc920a0Smrg
277cdc920a0Smrg   if (errCode != EGL_SUCCESS) {
278cdc920a0Smrg      const char *s;
2794a49301eSmrg
2804a49301eSmrg      switch (errCode) {
2814a49301eSmrg      case EGL_BAD_ACCESS:
2824a49301eSmrg         s = "EGL_BAD_ACCESS";
2834a49301eSmrg         break;
2844a49301eSmrg      case EGL_BAD_ALLOC:
2854a49301eSmrg         s = "EGL_BAD_ALLOC";
2864a49301eSmrg         break;
2874a49301eSmrg      case EGL_BAD_ATTRIBUTE:
2884a49301eSmrg         s = "EGL_BAD_ATTRIBUTE";
2894a49301eSmrg         break;
2904a49301eSmrg      case EGL_BAD_CONFIG:
2914a49301eSmrg         s = "EGL_BAD_CONFIG";
2924a49301eSmrg         break;
2934a49301eSmrg      case EGL_BAD_CONTEXT:
2944a49301eSmrg         s = "EGL_BAD_CONTEXT";
2954a49301eSmrg         break;
2964a49301eSmrg      case EGL_BAD_CURRENT_SURFACE:
2974a49301eSmrg         s = "EGL_BAD_CURRENT_SURFACE";
2984a49301eSmrg         break;
2994a49301eSmrg      case EGL_BAD_DISPLAY:
3004a49301eSmrg         s = "EGL_BAD_DISPLAY";
3014a49301eSmrg         break;
3024a49301eSmrg      case EGL_BAD_MATCH:
3034a49301eSmrg         s = "EGL_BAD_MATCH";
3044a49301eSmrg         break;
3054a49301eSmrg      case EGL_BAD_NATIVE_PIXMAP:
3064a49301eSmrg         s = "EGL_BAD_NATIVE_PIXMAP";
3074a49301eSmrg         break;
3084a49301eSmrg      case EGL_BAD_NATIVE_WINDOW:
3094a49301eSmrg         s = "EGL_BAD_NATIVE_WINDOW";
3104a49301eSmrg         break;
3114a49301eSmrg      case EGL_BAD_PARAMETER:
3124a49301eSmrg         s = "EGL_BAD_PARAMETER";
3134a49301eSmrg         break;
3144a49301eSmrg      case EGL_BAD_SURFACE:
3154a49301eSmrg         s = "EGL_BAD_SURFACE";
3164a49301eSmrg         break;
3173464ebd5Sriastradh      case EGL_NOT_INITIALIZED:
3183464ebd5Sriastradh         s = "EGL_NOT_INITIALIZED";
3193464ebd5Sriastradh         break;
3203464ebd5Sriastradh#ifdef EGL_MESA_screen_surface
3214a49301eSmrg      case EGL_BAD_SCREEN_MESA:
3224a49301eSmrg         s = "EGL_BAD_SCREEN_MESA";
3234a49301eSmrg         break;
3244a49301eSmrg      case EGL_BAD_MODE_MESA:
3254a49301eSmrg         s = "EGL_BAD_MODE_MESA";
3264a49301eSmrg         break;
3273464ebd5Sriastradh#endif
3284a49301eSmrg      default:
3293464ebd5Sriastradh         s = "other EGL error";
3304a49301eSmrg      }
3314a49301eSmrg      _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
3324a49301eSmrg   }
3334a49301eSmrg
3344a49301eSmrg   return EGL_FALSE;
3354a49301eSmrg}
336