eglcurrent.c revision cdc920a0
14a49301eSmrg#include <stdlib.h>
24a49301eSmrg#include <string.h>
3cdc920a0Smrg#include "eglglobals.h"
44a49301eSmrg#include "egllog.h"
54a49301eSmrg#include "eglmutex.h"
6cdc920a0Smrg#include "eglcurrent.h"
74a49301eSmrg
84a49301eSmrg
94a49301eSmrg/* This should be kept in sync with _eglInitThreadInfo() */
104a49301eSmrg#define _EGL_THREAD_INFO_INITIALIZER \
114a49301eSmrg   { EGL_SUCCESS, { NULL }, 0 }
124a49301eSmrg
134a49301eSmrg/* a fallback thread info to guarantee that every thread always has one */
144a49301eSmrgstatic _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
154a49301eSmrg
164a49301eSmrg
174a49301eSmrg#ifdef GLX_USE_TLS
184a49301eSmrgstatic __thread const _EGLThreadInfo *_egl_TSD
194a49301eSmrg   __attribute__ ((tls_model("initial-exec")));
204a49301eSmrg
214a49301eSmrgstatic INLINE void _eglSetTSD(const _EGLThreadInfo *t)
224a49301eSmrg{
234a49301eSmrg   _egl_TSD = t;
244a49301eSmrg}
254a49301eSmrg
264a49301eSmrgstatic INLINE _EGLThreadInfo *_eglGetTSD(void)
274a49301eSmrg{
284a49301eSmrg   return (_EGLThreadInfo *) _egl_TSD;
294a49301eSmrg}
304a49301eSmrg
314a49301eSmrgstatic INLINE void _eglFiniTSD(void)
324a49301eSmrg{
334a49301eSmrg}
344a49301eSmrg
354a49301eSmrgstatic INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
364a49301eSmrg{
374a49301eSmrg   /* TODO destroy TSD */
384a49301eSmrg   (void) dtor;
394a49301eSmrg   (void) _eglFiniTSD;
404a49301eSmrg   return EGL_TRUE;
414a49301eSmrg}
424a49301eSmrg
434a49301eSmrg#elif PTHREADS
444a49301eSmrg#include <pthread.h>
454a49301eSmrg
464a49301eSmrgstatic _EGL_DECLARE_MUTEX(_egl_TSDMutex);
474a49301eSmrgstatic EGLBoolean _egl_TSDInitialized;
484a49301eSmrgstatic pthread_key_t _egl_TSD;
494a49301eSmrgstatic void (*_egl_FreeTSD)(_EGLThreadInfo *);
504a49301eSmrg
514a49301eSmrgstatic INLINE void _eglSetTSD(const _EGLThreadInfo *t)
524a49301eSmrg{
534a49301eSmrg   pthread_setspecific(_egl_TSD, (const void *) t);
544a49301eSmrg}
554a49301eSmrg
564a49301eSmrgstatic INLINE _EGLThreadInfo *_eglGetTSD(void)
574a49301eSmrg{
584a49301eSmrg   return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD);
594a49301eSmrg}
604a49301eSmrg
614a49301eSmrgstatic INLINE void _eglFiniTSD(void)
624a49301eSmrg{
634a49301eSmrg   _eglLockMutex(&_egl_TSDMutex);
644a49301eSmrg   if (_egl_TSDInitialized) {
654a49301eSmrg      _EGLThreadInfo *t = _eglGetTSD();
664a49301eSmrg
674a49301eSmrg      _egl_TSDInitialized = EGL_FALSE;
684a49301eSmrg      if (t && _egl_FreeTSD)
694a49301eSmrg         _egl_FreeTSD((void *) t);
704a49301eSmrg      pthread_key_delete(_egl_TSD);
714a49301eSmrg   }
724a49301eSmrg   _eglUnlockMutex(&_egl_TSDMutex);
734a49301eSmrg}
744a49301eSmrg
754a49301eSmrgstatic INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
764a49301eSmrg{
774a49301eSmrg   if (!_egl_TSDInitialized) {
784a49301eSmrg      _eglLockMutex(&_egl_TSDMutex);
794a49301eSmrg
804a49301eSmrg      /* check again after acquiring lock */
814a49301eSmrg      if (!_egl_TSDInitialized) {
824a49301eSmrg         if (pthread_key_create(&_egl_TSD, (void (*)(void *)) dtor) != 0) {
834a49301eSmrg            _eglUnlockMutex(&_egl_TSDMutex);
844a49301eSmrg            return EGL_FALSE;
854a49301eSmrg         }
864a49301eSmrg         _egl_FreeTSD = dtor;
874a49301eSmrg         _eglAddAtExitCall(_eglFiniTSD);
884a49301eSmrg         _egl_TSDInitialized = EGL_TRUE;
894a49301eSmrg      }
904a49301eSmrg
914a49301eSmrg      _eglUnlockMutex(&_egl_TSDMutex);
924a49301eSmrg   }
934a49301eSmrg
944a49301eSmrg   return EGL_TRUE;
954a49301eSmrg}
964a49301eSmrg
974a49301eSmrg#else /* PTHREADS */
984a49301eSmrgstatic const _EGLThreadInfo *_egl_TSD;
994a49301eSmrgstatic void (*_egl_FreeTSD)(_EGLThreadInfo *);
1004a49301eSmrg
1014a49301eSmrgstatic INLINE void _eglSetTSD(const _EGLThreadInfo *t)
1024a49301eSmrg{
1034a49301eSmrg   _egl_TSD = t;
1044a49301eSmrg}
1054a49301eSmrg
1064a49301eSmrgstatic INLINE _EGLThreadInfo *_eglGetTSD(void)
1074a49301eSmrg{
1084a49301eSmrg   return (_EGLThreadInfo *) _egl_TSD;
1094a49301eSmrg}
1104a49301eSmrg
1114a49301eSmrgstatic INLINE void _eglFiniTSD(void)
1124a49301eSmrg{
1134a49301eSmrg   if (_egl_FreeTSD && _egl_TSD)
1144a49301eSmrg      _egl_FreeTSD((_EGLThreadInfo *) _egl_TSD);
1154a49301eSmrg}
1164a49301eSmrg
1174a49301eSmrgstatic INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
1184a49301eSmrg{
1194a49301eSmrg   if (!_egl_FreeTSD && dtor) {
1204a49301eSmrg      _egl_FreeTSD = dtor;
1214a49301eSmrg      _eglAddAtExitCall(_eglFiniTSD);
1224a49301eSmrg   }
1234a49301eSmrg   return EGL_TRUE;
1244a49301eSmrg}
1254a49301eSmrg
1264a49301eSmrg#endif /* !PTHREADS */
1274a49301eSmrg
1284a49301eSmrg
1294a49301eSmrgstatic void
1304a49301eSmrg_eglInitThreadInfo(_EGLThreadInfo *t)
1314a49301eSmrg{
1324a49301eSmrg   memset(t, 0, sizeof(*t));
1334a49301eSmrg   t->LastError = EGL_SUCCESS;
1344a49301eSmrg   /* default, per EGL spec */
1354a49301eSmrg   t->CurrentAPIIndex = _eglConvertApiToIndex(EGL_OPENGL_ES_API);
1364a49301eSmrg}
1374a49301eSmrg
1384a49301eSmrg
1394a49301eSmrg/**
1404a49301eSmrg * Allocate and init a new _EGLThreadInfo object.
1414a49301eSmrg */
1424a49301eSmrgstatic _EGLThreadInfo *
1434a49301eSmrg_eglCreateThreadInfo(void)
1444a49301eSmrg{
1454a49301eSmrg   _EGLThreadInfo *t = (_EGLThreadInfo *) calloc(1, sizeof(_EGLThreadInfo));
1464a49301eSmrg   if (t)
1474a49301eSmrg      _eglInitThreadInfo(t);
1484a49301eSmrg   else
1494a49301eSmrg      t = &dummy_thread;
1504a49301eSmrg   return t;
1514a49301eSmrg}
1524a49301eSmrg
1534a49301eSmrg
1544a49301eSmrg/**
1554a49301eSmrg * Delete/free a _EGLThreadInfo object.
1564a49301eSmrg */
1574a49301eSmrgstatic void
1584a49301eSmrg_eglDestroyThreadInfo(_EGLThreadInfo *t)
1594a49301eSmrg{
1604a49301eSmrg   if (t != &dummy_thread)
1614a49301eSmrg      free(t);
1624a49301eSmrg}
1634a49301eSmrg
1644a49301eSmrg
1654a49301eSmrg/**
1664a49301eSmrg * Make sure TSD is initialized and return current value.
1674a49301eSmrg */
1684a49301eSmrgstatic INLINE _EGLThreadInfo *
1694a49301eSmrg_eglCheckedGetTSD(void)
1704a49301eSmrg{
1714a49301eSmrg   if (_eglInitTSD(&_eglDestroyThreadInfo) != EGL_TRUE) {
1724a49301eSmrg      _eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
1734a49301eSmrg      return NULL;
1744a49301eSmrg   }
1754a49301eSmrg
1764a49301eSmrg   return _eglGetTSD();
1774a49301eSmrg}
1784a49301eSmrg
1794a49301eSmrg
1804a49301eSmrg/**
1814a49301eSmrg * Return the calling thread's thread info.
1824a49301eSmrg * If the calling thread nevers calls this function before, or if its thread
1834a49301eSmrg * info was destroyed, a new one is created.  This function never returns NULL.
1844a49301eSmrg * In the case allocation fails, a dummy one is returned.  See also
1854a49301eSmrg * _eglIsCurrentThreadDummy.
1864a49301eSmrg */
1874a49301eSmrg_EGLThreadInfo *
1884a49301eSmrg_eglGetCurrentThread(void)
1894a49301eSmrg{
1904a49301eSmrg   _EGLThreadInfo *t = _eglCheckedGetTSD();
1914a49301eSmrg   if (!t) {
1924a49301eSmrg      t = _eglCreateThreadInfo();
1934a49301eSmrg      _eglSetTSD(t);
1944a49301eSmrg   }
1954a49301eSmrg
1964a49301eSmrg   return t;
1974a49301eSmrg}
1984a49301eSmrg
1994a49301eSmrg
2004a49301eSmrg/**
2014a49301eSmrg * Destroy the calling thread's thread info.
2024a49301eSmrg */
2034a49301eSmrgvoid
2044a49301eSmrg_eglDestroyCurrentThread(void)
2054a49301eSmrg{
2064a49301eSmrg   _EGLThreadInfo *t = _eglCheckedGetTSD();
2074a49301eSmrg   if (t) {
2084a49301eSmrg      _eglDestroyThreadInfo(t);
2094a49301eSmrg      _eglSetTSD(NULL);
2104a49301eSmrg   }
2114a49301eSmrg}
2124a49301eSmrg
2134a49301eSmrg
2144a49301eSmrg/**
2154a49301eSmrg * Return true if the calling thread's thread info is dummy.
2164a49301eSmrg * A dummy thread info is shared by all threads and should not be modified.
2174a49301eSmrg * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
2184a49301eSmrg * before updating the thread info.
2194a49301eSmrg */
2204a49301eSmrgEGLBoolean
2214a49301eSmrg_eglIsCurrentThreadDummy(void)
2224a49301eSmrg{
2234a49301eSmrg   _EGLThreadInfo *t = _eglCheckedGetTSD();
2244a49301eSmrg   return (!t || t == &dummy_thread);
2254a49301eSmrg}
2264a49301eSmrg
2274a49301eSmrg
2284a49301eSmrg/**
229cdc920a0Smrg * Return the currently bound context of the given API, or NULL.
2304a49301eSmrg */
231cdc920a0SmrgPUBLIC _EGLContext *
232cdc920a0Smrg_eglGetAPIContext(EGLenum api)
2334a49301eSmrg{
2344a49301eSmrg   _EGLThreadInfo *t = _eglGetCurrentThread();
235cdc920a0Smrg   return t->CurrentContexts[_eglConvertApiToIndex(api)];
2364a49301eSmrg}
2374a49301eSmrg
2384a49301eSmrg
2394a49301eSmrg/**
240cdc920a0Smrg * Return the currently bound context of the current API, or NULL.
2414a49301eSmrg */
242cdc920a0Smrg_EGLContext *
243cdc920a0Smrg_eglGetCurrentContext(void)
2444a49301eSmrg{
2454a49301eSmrg   _EGLThreadInfo *t = _eglGetCurrentThread();
246cdc920a0Smrg   return t->CurrentContexts[t->CurrentAPIIndex];
2474a49301eSmrg}
2484a49301eSmrg
2494a49301eSmrg
2504a49301eSmrg/**
251cdc920a0Smrg * Record EGL error code and return EGL_FALSE.
2524a49301eSmrg */
2534a49301eSmrgEGLBoolean
2544a49301eSmrg_eglError(EGLint errCode, const char *msg)
2554a49301eSmrg{
2564a49301eSmrg   _EGLThreadInfo *t = _eglGetCurrentThread();
2574a49301eSmrg
2584a49301eSmrg   if (t == &dummy_thread)
2594a49301eSmrg      return EGL_FALSE;
2604a49301eSmrg
261cdc920a0Smrg   t->LastError = errCode;
262cdc920a0Smrg
263cdc920a0Smrg   if (errCode != EGL_SUCCESS) {
264cdc920a0Smrg      const char *s;
2654a49301eSmrg
2664a49301eSmrg      switch (errCode) {
2674a49301eSmrg      case EGL_BAD_ACCESS:
2684a49301eSmrg         s = "EGL_BAD_ACCESS";
2694a49301eSmrg         break;
2704a49301eSmrg      case EGL_BAD_ALLOC:
2714a49301eSmrg         s = "EGL_BAD_ALLOC";
2724a49301eSmrg         break;
2734a49301eSmrg      case EGL_BAD_ATTRIBUTE:
2744a49301eSmrg         s = "EGL_BAD_ATTRIBUTE";
2754a49301eSmrg         break;
2764a49301eSmrg      case EGL_BAD_CONFIG:
2774a49301eSmrg         s = "EGL_BAD_CONFIG";
2784a49301eSmrg         break;
2794a49301eSmrg      case EGL_BAD_CONTEXT:
2804a49301eSmrg         s = "EGL_BAD_CONTEXT";
2814a49301eSmrg         break;
2824a49301eSmrg      case EGL_BAD_CURRENT_SURFACE:
2834a49301eSmrg         s = "EGL_BAD_CURRENT_SURFACE";
2844a49301eSmrg         break;
2854a49301eSmrg      case EGL_BAD_DISPLAY:
2864a49301eSmrg         s = "EGL_BAD_DISPLAY";
2874a49301eSmrg         break;
2884a49301eSmrg      case EGL_BAD_MATCH:
2894a49301eSmrg         s = "EGL_BAD_MATCH";
2904a49301eSmrg         break;
2914a49301eSmrg      case EGL_BAD_NATIVE_PIXMAP:
2924a49301eSmrg         s = "EGL_BAD_NATIVE_PIXMAP";
2934a49301eSmrg         break;
2944a49301eSmrg      case EGL_BAD_NATIVE_WINDOW:
2954a49301eSmrg         s = "EGL_BAD_NATIVE_WINDOW";
2964a49301eSmrg         break;
2974a49301eSmrg      case EGL_BAD_PARAMETER:
2984a49301eSmrg         s = "EGL_BAD_PARAMETER";
2994a49301eSmrg         break;
3004a49301eSmrg      case EGL_BAD_SURFACE:
3014a49301eSmrg         s = "EGL_BAD_SURFACE";
3024a49301eSmrg         break;
3034a49301eSmrg      case EGL_BAD_SCREEN_MESA:
3044a49301eSmrg         s = "EGL_BAD_SCREEN_MESA";
3054a49301eSmrg         break;
3064a49301eSmrg      case EGL_BAD_MODE_MESA:
3074a49301eSmrg         s = "EGL_BAD_MODE_MESA";
3084a49301eSmrg         break;
3094a49301eSmrg      default:
3104a49301eSmrg         s = "other";
3114a49301eSmrg      }
3124a49301eSmrg      _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
3134a49301eSmrg   }
3144a49301eSmrg
3154a49301eSmrg   return EGL_FALSE;
3164a49301eSmrg}
317