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