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