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
41 static __THREAD_INITIAL_EXEC _EGLThreadInfo _egl_TLS = {
42 .inited = false
43 };
44
45 static void
_eglInitThreadInfo(_EGLThreadInfo * t)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 *
_eglGetCurrentThread(void)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 */
75 void
_eglDestroyCurrentThread(void)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 *
_eglGetCurrentContext(void)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 */
97 static EGLBoolean
_eglInternalError(EGLint errCode,const char * msg)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
156 EGLBoolean
_eglError(EGLint errCode,const char * msg)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
173 void
_eglDebugReport(EGLenum error,const char * funcName,EGLint type,const char * message,...)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