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 2901e04c3fSmrg#include <stdio.h> 304a49301eSmrg#include <stdlib.h> 314a49301eSmrg#include <string.h> 3201e04c3fSmrg#include <stdarg.h> 3301e04c3fSmrg#include "c99_compat.h" 3401e04c3fSmrg#include "c11/threads.h" 357ec681f3Smrg#include "util/u_thread.h" 367ec681f3Smrg#include "util/u_string.h" 3701e04c3fSmrg 384a49301eSmrg#include "egllog.h" 39cdc920a0Smrg#include "eglcurrent.h" 403464ebd5Sriastradh#include "eglglobals.h" 414a49301eSmrg 424a49301eSmrg/* a fallback thread info to guarantee that every thread always has one */ 4301e04c3fSmrgstatic _EGLThreadInfo dummy_thread; 4401e04c3fSmrgstatic mtx_t _egl_TSDMutex = _MTX_INITIALIZER_NP; 454a49301eSmrgstatic EGLBoolean _egl_TSDInitialized; 4601e04c3fSmrgstatic tss_t _egl_TSD; 477e102996Smayastatic void _eglDestroyThreadInfo(_EGLThreadInfo *t); 484a49301eSmrg 497ec681f3Smrg#ifdef USE_ELF_TLS 507ec681f3Smrgstatic __THREAD_INITIAL_EXEC const _EGLThreadInfo *_egl_TLS; 513464ebd5Sriastradh#endif 523464ebd5Sriastradh 5301e04c3fSmrgstatic inline void _eglSetTSD(const _EGLThreadInfo *t) 544a49301eSmrg{ 5501e04c3fSmrg tss_set(_egl_TSD, (void *) t); 567ec681f3Smrg#ifdef USE_ELF_TLS 573464ebd5Sriastradh _egl_TLS = t; 583464ebd5Sriastradh#endif 594a49301eSmrg} 604a49301eSmrg 6101e04c3fSmrgstatic inline _EGLThreadInfo *_eglGetTSD(void) 624a49301eSmrg{ 637ec681f3Smrg#ifdef USE_ELF_TLS 643464ebd5Sriastradh return (_EGLThreadInfo *) _egl_TLS; 653464ebd5Sriastradh#else 6601e04c3fSmrg return (_EGLThreadInfo *) tss_get(_egl_TSD); 673464ebd5Sriastradh#endif 684a49301eSmrg} 694a49301eSmrg 7001e04c3fSmrgstatic inline void _eglFiniTSD(void) 714a49301eSmrg{ 7201e04c3fSmrg mtx_lock(&_egl_TSDMutex); 734a49301eSmrg if (_egl_TSDInitialized) { 744a49301eSmrg _EGLThreadInfo *t = _eglGetTSD(); 754a49301eSmrg 764a49301eSmrg _egl_TSDInitialized = EGL_FALSE; 777e102996Smaya _eglDestroyThreadInfo(t); 7801e04c3fSmrg tss_delete(_egl_TSD); 794a49301eSmrg } 8001e04c3fSmrg mtx_unlock(&_egl_TSDMutex); 814a49301eSmrg} 824a49301eSmrg 837e102996Smayastatic inline EGLBoolean _eglInitTSD() 844a49301eSmrg{ 854a49301eSmrg if (!_egl_TSDInitialized) { 8601e04c3fSmrg mtx_lock(&_egl_TSDMutex); 874a49301eSmrg 884a49301eSmrg /* check again after acquiring lock */ 894a49301eSmrg if (!_egl_TSDInitialized) { 907e102996Smaya if (tss_create(&_egl_TSD, (void (*)(void *)) _eglDestroyThreadInfo) != thrd_success) { 9101e04c3fSmrg mtx_unlock(&_egl_TSDMutex); 924a49301eSmrg return EGL_FALSE; 934a49301eSmrg } 944a49301eSmrg _eglAddAtExitCall(_eglFiniTSD); 954a49301eSmrg _egl_TSDInitialized = EGL_TRUE; 964a49301eSmrg } 974a49301eSmrg 9801e04c3fSmrg mtx_unlock(&_egl_TSDMutex); 994a49301eSmrg } 1004a49301eSmrg 1014a49301eSmrg return EGL_TRUE; 1024a49301eSmrg} 1034a49301eSmrg 1044a49301eSmrgstatic void 1054a49301eSmrg_eglInitThreadInfo(_EGLThreadInfo *t) 1064a49301eSmrg{ 1074a49301eSmrg t->LastError = EGL_SUCCESS; 1084a49301eSmrg /* default, per EGL spec */ 10901e04c3fSmrg t->CurrentAPI = EGL_OPENGL_ES_API; 1104a49301eSmrg} 1114a49301eSmrg 1124a49301eSmrg 1134a49301eSmrg/** 1144a49301eSmrg * Allocate and init a new _EGLThreadInfo object. 1154a49301eSmrg */ 1164a49301eSmrgstatic _EGLThreadInfo * 1174a49301eSmrg_eglCreateThreadInfo(void) 1184a49301eSmrg{ 119af69d88dSmrg _EGLThreadInfo *t = calloc(1, sizeof(_EGLThreadInfo)); 12001e04c3fSmrg if (!t) 1214a49301eSmrg t = &dummy_thread; 12201e04c3fSmrg 12301e04c3fSmrg _eglInitThreadInfo(t); 1244a49301eSmrg return t; 1254a49301eSmrg} 1264a49301eSmrg 1274a49301eSmrg 1284a49301eSmrg/** 1294a49301eSmrg * Delete/free a _EGLThreadInfo object. 1304a49301eSmrg */ 1314a49301eSmrgstatic void 1324a49301eSmrg_eglDestroyThreadInfo(_EGLThreadInfo *t) 1334a49301eSmrg{ 1347ec681f3Smrg if (t != &dummy_thread) { 1354a49301eSmrg free(t); 1367ec681f3Smrg#ifdef USE_ELF_TLS 1377ec681f3Smrg /* Reset the TLS also here, otherwise 1387ec681f3Smrg * it will be having a dangling pointer */ 1397ec681f3Smrg _egl_TLS = NULL; 1407ec681f3Smrg#endif 1417ec681f3Smrg } 1424a49301eSmrg} 1434a49301eSmrg 1444a49301eSmrg 1454a49301eSmrg/** 1464a49301eSmrg * Make sure TSD is initialized and return current value. 1474a49301eSmrg */ 14801e04c3fSmrgstatic inline _EGLThreadInfo * 1494a49301eSmrg_eglCheckedGetTSD(void) 1504a49301eSmrg{ 1517e102996Smaya if (_eglInitTSD() != EGL_TRUE) { 1524a49301eSmrg _eglLog(_EGL_FATAL, "failed to initialize \"current\" system"); 1534a49301eSmrg return NULL; 1544a49301eSmrg } 1554a49301eSmrg 1564a49301eSmrg return _eglGetTSD(); 1574a49301eSmrg} 1584a49301eSmrg 1594a49301eSmrg 1604a49301eSmrg/** 1614a49301eSmrg * Return the calling thread's thread info. 1624a49301eSmrg * If the calling thread nevers calls this function before, or if its thread 1634a49301eSmrg * info was destroyed, a new one is created. This function never returns NULL. 1644a49301eSmrg * In the case allocation fails, a dummy one is returned. See also 1654a49301eSmrg * _eglIsCurrentThreadDummy. 1664a49301eSmrg */ 1674a49301eSmrg_EGLThreadInfo * 1684a49301eSmrg_eglGetCurrentThread(void) 1694a49301eSmrg{ 1704a49301eSmrg _EGLThreadInfo *t = _eglCheckedGetTSD(); 1714a49301eSmrg if (!t) { 1724a49301eSmrg t = _eglCreateThreadInfo(); 1734a49301eSmrg _eglSetTSD(t); 1744a49301eSmrg } 1754a49301eSmrg 1764a49301eSmrg return t; 1774a49301eSmrg} 1784a49301eSmrg 1794a49301eSmrg 1804a49301eSmrg/** 1814a49301eSmrg * Destroy the calling thread's thread info. 1824a49301eSmrg */ 1834a49301eSmrgvoid 1844a49301eSmrg_eglDestroyCurrentThread(void) 1854a49301eSmrg{ 1864a49301eSmrg _EGLThreadInfo *t = _eglCheckedGetTSD(); 1874a49301eSmrg if (t) { 1884a49301eSmrg _eglDestroyThreadInfo(t); 1894a49301eSmrg _eglSetTSD(NULL); 1904a49301eSmrg } 1914a49301eSmrg} 1924a49301eSmrg 1934a49301eSmrg 1944a49301eSmrg/** 1954a49301eSmrg * Return true if the calling thread's thread info is dummy. 1964a49301eSmrg * A dummy thread info is shared by all threads and should not be modified. 1974a49301eSmrg * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness 1984a49301eSmrg * before updating the thread info. 1994a49301eSmrg */ 2004a49301eSmrgEGLBoolean 2014a49301eSmrg_eglIsCurrentThreadDummy(void) 2024a49301eSmrg{ 2034a49301eSmrg _EGLThreadInfo *t = _eglCheckedGetTSD(); 2044a49301eSmrg return (!t || t == &dummy_thread); 2054a49301eSmrg} 2064a49301eSmrg 2074a49301eSmrg 2084a49301eSmrg/** 209cdc920a0Smrg * Return the currently bound context of the current API, or NULL. 2104a49301eSmrg */ 211cdc920a0Smrg_EGLContext * 212cdc920a0Smrg_eglGetCurrentContext(void) 2134a49301eSmrg{ 2144a49301eSmrg _EGLThreadInfo *t = _eglGetCurrentThread(); 21501e04c3fSmrg return t->CurrentContext; 2164a49301eSmrg} 2174a49301eSmrg 2184a49301eSmrg 2194a49301eSmrg/** 220cdc920a0Smrg * Record EGL error code and return EGL_FALSE. 2214a49301eSmrg */ 22201e04c3fSmrgstatic EGLBoolean 22301e04c3fSmrg_eglInternalError(EGLint errCode, const char *msg) 2244a49301eSmrg{ 2254a49301eSmrg _EGLThreadInfo *t = _eglGetCurrentThread(); 2264a49301eSmrg 2274a49301eSmrg if (t == &dummy_thread) 2284a49301eSmrg return EGL_FALSE; 2294a49301eSmrg 230cdc920a0Smrg t->LastError = errCode; 231cdc920a0Smrg 232cdc920a0Smrg if (errCode != EGL_SUCCESS) { 233cdc920a0Smrg const char *s; 2344a49301eSmrg 2354a49301eSmrg switch (errCode) { 2364a49301eSmrg case EGL_BAD_ACCESS: 2374a49301eSmrg s = "EGL_BAD_ACCESS"; 2384a49301eSmrg break; 2394a49301eSmrg case EGL_BAD_ALLOC: 2404a49301eSmrg s = "EGL_BAD_ALLOC"; 2414a49301eSmrg break; 2424a49301eSmrg case EGL_BAD_ATTRIBUTE: 2434a49301eSmrg s = "EGL_BAD_ATTRIBUTE"; 2444a49301eSmrg break; 2454a49301eSmrg case EGL_BAD_CONFIG: 2464a49301eSmrg s = "EGL_BAD_CONFIG"; 2474a49301eSmrg break; 2484a49301eSmrg case EGL_BAD_CONTEXT: 2494a49301eSmrg s = "EGL_BAD_CONTEXT"; 2504a49301eSmrg break; 2514a49301eSmrg case EGL_BAD_CURRENT_SURFACE: 2524a49301eSmrg s = "EGL_BAD_CURRENT_SURFACE"; 2534a49301eSmrg break; 2544a49301eSmrg case EGL_BAD_DISPLAY: 2554a49301eSmrg s = "EGL_BAD_DISPLAY"; 2564a49301eSmrg break; 2574a49301eSmrg case EGL_BAD_MATCH: 2584a49301eSmrg s = "EGL_BAD_MATCH"; 2594a49301eSmrg break; 2604a49301eSmrg case EGL_BAD_NATIVE_PIXMAP: 2614a49301eSmrg s = "EGL_BAD_NATIVE_PIXMAP"; 2624a49301eSmrg break; 2634a49301eSmrg case EGL_BAD_NATIVE_WINDOW: 2644a49301eSmrg s = "EGL_BAD_NATIVE_WINDOW"; 2654a49301eSmrg break; 2664a49301eSmrg case EGL_BAD_PARAMETER: 2674a49301eSmrg s = "EGL_BAD_PARAMETER"; 2684a49301eSmrg break; 2694a49301eSmrg case EGL_BAD_SURFACE: 2704a49301eSmrg s = "EGL_BAD_SURFACE"; 2714a49301eSmrg break; 2723464ebd5Sriastradh case EGL_NOT_INITIALIZED: 2733464ebd5Sriastradh s = "EGL_NOT_INITIALIZED"; 2743464ebd5Sriastradh break; 2754a49301eSmrg default: 2763464ebd5Sriastradh s = "other EGL error"; 2774a49301eSmrg } 2784a49301eSmrg _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg); 2794a49301eSmrg } 2804a49301eSmrg 2814a49301eSmrg return EGL_FALSE; 2824a49301eSmrg} 28301e04c3fSmrg 28401e04c3fSmrgEGLBoolean 28501e04c3fSmrg_eglError(EGLint errCode, const char *msg) 28601e04c3fSmrg{ 28701e04c3fSmrg if (errCode != EGL_SUCCESS) { 28801e04c3fSmrg EGLint type; 28901e04c3fSmrg if (errCode == EGL_BAD_ALLOC) 29001e04c3fSmrg type = EGL_DEBUG_MSG_CRITICAL_KHR; 29101e04c3fSmrg else 29201e04c3fSmrg type = EGL_DEBUG_MSG_ERROR_KHR; 29301e04c3fSmrg 29401e04c3fSmrg _eglDebugReport(errCode, NULL, type, msg); 29501e04c3fSmrg } else 29601e04c3fSmrg _eglInternalError(errCode, msg); 29701e04c3fSmrg 29801e04c3fSmrg return EGL_FALSE; 29901e04c3fSmrg} 30001e04c3fSmrg 30101e04c3fSmrgvoid 30201e04c3fSmrg_eglDebugReport(EGLenum error, const char *funcName, 30301e04c3fSmrg EGLint type, const char *message, ...) 30401e04c3fSmrg{ 30501e04c3fSmrg _EGLThreadInfo *thr = _eglGetCurrentThread(); 30601e04c3fSmrg EGLDEBUGPROCKHR callback = NULL; 30701e04c3fSmrg va_list args; 30801e04c3fSmrg 30901e04c3fSmrg if (funcName == NULL) 31001e04c3fSmrg funcName = thr->CurrentFuncName; 31101e04c3fSmrg 31201e04c3fSmrg mtx_lock(_eglGlobal.Mutex); 31301e04c3fSmrg if (_eglGlobal.debugTypesEnabled & DebugBitFromType(type)) 31401e04c3fSmrg callback = _eglGlobal.debugCallback; 31501e04c3fSmrg 31601e04c3fSmrg mtx_unlock(_eglGlobal.Mutex); 31701e04c3fSmrg 3187e102996Smaya char *message_buf = NULL; 3197e102996Smaya if (message != NULL) { 3207e102996Smaya va_start(args, message); 3217e102996Smaya if (vasprintf(&message_buf, message, args) < 0) 3227e102996Smaya message_buf = NULL; 3237e102996Smaya va_end(args); 3247e102996Smaya } 32501e04c3fSmrg 3267e102996Smaya if (callback != NULL) { 3277e102996Smaya callback(error, funcName, type, thr->Label, thr->CurrentObjectLabel, 3287e102996Smaya message_buf); 3297e102996Smaya } 33001e04c3fSmrg 3317e102996Smaya if (type == EGL_DEBUG_MSG_CRITICAL_KHR || type == EGL_DEBUG_MSG_ERROR_KHR) { 3327e102996Smaya char *func_message_buf = NULL; 3337e102996Smaya /* Note: _eglError() is often called with msg == thr->currentFuncName */ 3347e102996Smaya if (message_buf && funcName && strcmp(message_buf, funcName) != 0) { 3357e102996Smaya if (asprintf(&func_message_buf, "%s: %s", funcName, message_buf) < 0) 3367e102996Smaya func_message_buf = NULL; 33701e04c3fSmrg } 3387e102996Smaya _eglInternalError(error, func_message_buf ? func_message_buf : funcName); 3397e102996Smaya free(func_message_buf); 34001e04c3fSmrg } 3417e102996Smaya free(message_buf); 34201e04c3fSmrg} 343