1/************************************************************************** 2 * 3 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com> 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 * DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <stdarg.h> 33#include "c11/threads.h" 34#include "util/u_thread.h" 35#include "util/u_string.h" 36 37#include "egllog.h" 38#include "eglcurrent.h" 39#include "eglglobals.h" 40 41static __THREAD_INITIAL_EXEC _EGLThreadInfo _egl_TLS = { 42 .inited = false 43}; 44 45static void 46_eglInitThreadInfo(_EGLThreadInfo *t) 47{ 48 t->LastError = EGL_SUCCESS; 49 /* default, per EGL spec */ 50 t->CurrentAPI = EGL_OPENGL_ES_API; 51} 52 53 54/** 55 * Return the calling thread's thread info. 56 * If the calling thread nevers calls this function before, or if its thread 57 * info was destroyed, reinitialize it. This function never returns NULL. 58 */ 59_EGLThreadInfo * 60_eglGetCurrentThread(void) 61{ 62 _EGLThreadInfo *current = &_egl_TLS; 63 if (unlikely(!current->inited)) { 64 memset(current, 0, sizeof(current[0])); 65 _eglInitThreadInfo(current); 66 current->inited = true; 67 } 68 return current; 69} 70 71 72/** 73 * Destroy the calling thread's thread info. 74 */ 75void 76_eglDestroyCurrentThread(void) 77{ 78 _EGLThreadInfo *t = _eglGetCurrentThread(); 79 t->inited = false; 80} 81 82 83/** 84 * Return the currently bound context of the current API, or NULL. 85 */ 86_EGLContext * 87_eglGetCurrentContext(void) 88{ 89 _EGLThreadInfo *t = _eglGetCurrentThread(); 90 return t->CurrentContext; 91} 92 93 94/** 95 * Record EGL error code and return EGL_FALSE. 96 */ 97static EGLBoolean 98_eglInternalError(EGLint errCode, const char *msg) 99{ 100 _EGLThreadInfo *t = _eglGetCurrentThread(); 101 102 t->LastError = errCode; 103 104 if (errCode != EGL_SUCCESS) { 105 const char *s; 106 107 switch (errCode) { 108 case EGL_BAD_ACCESS: 109 s = "EGL_BAD_ACCESS"; 110 break; 111 case EGL_BAD_ALLOC: 112 s = "EGL_BAD_ALLOC"; 113 break; 114 case EGL_BAD_ATTRIBUTE: 115 s = "EGL_BAD_ATTRIBUTE"; 116 break; 117 case EGL_BAD_CONFIG: 118 s = "EGL_BAD_CONFIG"; 119 break; 120 case EGL_BAD_CONTEXT: 121 s = "EGL_BAD_CONTEXT"; 122 break; 123 case EGL_BAD_CURRENT_SURFACE: 124 s = "EGL_BAD_CURRENT_SURFACE"; 125 break; 126 case EGL_BAD_DISPLAY: 127 s = "EGL_BAD_DISPLAY"; 128 break; 129 case EGL_BAD_MATCH: 130 s = "EGL_BAD_MATCH"; 131 break; 132 case EGL_BAD_NATIVE_PIXMAP: 133 s = "EGL_BAD_NATIVE_PIXMAP"; 134 break; 135 case EGL_BAD_NATIVE_WINDOW: 136 s = "EGL_BAD_NATIVE_WINDOW"; 137 break; 138 case EGL_BAD_PARAMETER: 139 s = "EGL_BAD_PARAMETER"; 140 break; 141 case EGL_BAD_SURFACE: 142 s = "EGL_BAD_SURFACE"; 143 break; 144 case EGL_NOT_INITIALIZED: 145 s = "EGL_NOT_INITIALIZED"; 146 break; 147 default: 148 s = "other EGL error"; 149 } 150 _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg); 151 } 152 153 return EGL_FALSE; 154} 155 156EGLBoolean 157_eglError(EGLint errCode, const char *msg) 158{ 159 if (errCode != EGL_SUCCESS) { 160 EGLint type; 161 if (errCode == EGL_BAD_ALLOC) 162 type = EGL_DEBUG_MSG_CRITICAL_KHR; 163 else 164 type = EGL_DEBUG_MSG_ERROR_KHR; 165 166 _eglDebugReport(errCode, NULL, type, msg); 167 } else 168 _eglInternalError(errCode, msg); 169 170 return EGL_FALSE; 171} 172 173void 174_eglDebugReport(EGLenum error, const char *funcName, 175 EGLint type, const char *message, ...) 176{ 177 _EGLThreadInfo *thr = _eglGetCurrentThread(); 178 EGLDEBUGPROCKHR callback = NULL; 179 va_list args; 180 181 if (funcName == NULL) 182 funcName = thr->CurrentFuncName; 183 184 mtx_lock(_eglGlobal.Mutex); 185 if (_eglGlobal.debugTypesEnabled & DebugBitFromType(type)) 186 callback = _eglGlobal.debugCallback; 187 188 mtx_unlock(_eglGlobal.Mutex); 189 190 char *message_buf = NULL; 191 if (message != NULL) { 192 va_start(args, message); 193 if (vasprintf(&message_buf, message, args) < 0) 194 message_buf = NULL; 195 va_end(args); 196 } 197 198 if (callback != NULL) { 199 callback(error, funcName, type, thr->Label, thr->CurrentObjectLabel, 200 message_buf); 201 } 202 203 if (type == EGL_DEBUG_MSG_CRITICAL_KHR || type == EGL_DEBUG_MSG_ERROR_KHR) { 204 char *func_message_buf = NULL; 205 /* Note: _eglError() is often called with msg == thr->currentFuncName */ 206 if (message_buf && funcName && strcmp(message_buf, funcName) != 0) { 207 if (asprintf(&func_message_buf, "%s: %s", funcName, message_buf) < 0) 208 func_message_buf = NULL; 209 } 210 _eglInternalError(error, func_message_buf ? func_message_buf : funcName); 211 free(func_message_buf); 212 } 213 free(message_buf); 214} 215