• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "c99_compat.h"
34 #include "c11/threads.h"
35 #include "util/u_thread.h"
36 #include "util/u_string.h"
37 
38 #include "egllog.h"
39 #include "eglcurrent.h"
40 #include "eglglobals.h"
41 
42 /* a fallback thread info to guarantee that every thread always has one */
43 static _EGLThreadInfo dummy_thread;
44 static mtx_t _egl_TSDMutex = _MTX_INITIALIZER_NP;
45 static EGLBoolean _egl_TSDInitialized;
46 static tss_t _egl_TSD;
47 static void _eglDestroyThreadInfo(_EGLThreadInfo *t);
48 
49 #ifdef USE_ELF_TLS
50 static __THREAD_INITIAL_EXEC const _EGLThreadInfo *_egl_TLS;
51 #endif
52 
_eglSetTSD(const _EGLThreadInfo * t)53 static inline void _eglSetTSD(const _EGLThreadInfo *t)
54 {
55    tss_set(_egl_TSD, (void *) t);
56 #ifdef USE_ELF_TLS
57    _egl_TLS = t;
58 #endif
59 }
60 
_eglGetTSD(void)61 static inline _EGLThreadInfo *_eglGetTSD(void)
62 {
63 #ifdef USE_ELF_TLS
64    return (_EGLThreadInfo *) _egl_TLS;
65 #else
66    return (_EGLThreadInfo *) tss_get(_egl_TSD);
67 #endif
68 }
69 
_eglFiniTSD(void)70 static inline void _eglFiniTSD(void)
71 {
72    mtx_lock(&_egl_TSDMutex);
73    if (_egl_TSDInitialized) {
74       _EGLThreadInfo *t = _eglGetTSD();
75 
76       _egl_TSDInitialized = EGL_FALSE;
77       _eglDestroyThreadInfo(t);
78       tss_delete(_egl_TSD);
79    }
80    mtx_unlock(&_egl_TSDMutex);
81 }
82 
_eglInitTSD()83 static inline EGLBoolean _eglInitTSD()
84 {
85    if (!_egl_TSDInitialized) {
86       mtx_lock(&_egl_TSDMutex);
87 
88       /* check again after acquiring lock */
89       if (!_egl_TSDInitialized) {
90          if (tss_create(&_egl_TSD, (void (*)(void *)) _eglDestroyThreadInfo) != thrd_success) {
91             mtx_unlock(&_egl_TSDMutex);
92             return EGL_FALSE;
93          }
94          _eglAddAtExitCall(_eglFiniTSD);
95          _egl_TSDInitialized = EGL_TRUE;
96       }
97 
98       mtx_unlock(&_egl_TSDMutex);
99    }
100 
101    return EGL_TRUE;
102 }
103 
104 static void
_eglInitThreadInfo(_EGLThreadInfo * t)105 _eglInitThreadInfo(_EGLThreadInfo *t)
106 {
107    t->LastError = EGL_SUCCESS;
108    /* default, per EGL spec */
109    t->CurrentAPI = EGL_OPENGL_ES_API;
110 }
111 
112 
113 /**
114  * Allocate and init a new _EGLThreadInfo object.
115  */
116 static _EGLThreadInfo *
_eglCreateThreadInfo(void)117 _eglCreateThreadInfo(void)
118 {
119    _EGLThreadInfo *t = calloc(1, sizeof(_EGLThreadInfo));
120    if (!t)
121       t = &dummy_thread;
122 
123    _eglInitThreadInfo(t);
124    return t;
125 }
126 
127 
128 /**
129  * Delete/free a _EGLThreadInfo object.
130  */
131 static void
_eglDestroyThreadInfo(_EGLThreadInfo * t)132 _eglDestroyThreadInfo(_EGLThreadInfo *t)
133 {
134    if (t != &dummy_thread) {
135       free(t);
136 #ifdef USE_ELF_TLS
137       /* Reset the TLS also here, otherwise
138        * it will be having a dangling pointer */
139       _egl_TLS = NULL;
140 #endif
141    }
142 }
143 
144 
145 /**
146  * Make sure TSD is initialized and return current value.
147  */
148 static inline _EGLThreadInfo *
_eglCheckedGetTSD(void)149 _eglCheckedGetTSD(void)
150 {
151    if (_eglInitTSD() != EGL_TRUE) {
152       _eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
153       return NULL;
154    }
155 
156    return _eglGetTSD();
157 }
158 
159 
160 /**
161  * Return the calling thread's thread info.
162  * If the calling thread nevers calls this function before, or if its thread
163  * info was destroyed, a new one is created.  This function never returns NULL.
164  * In the case allocation fails, a dummy one is returned.  See also
165  * _eglIsCurrentThreadDummy.
166  */
167 _EGLThreadInfo *
_eglGetCurrentThread(void)168 _eglGetCurrentThread(void)
169 {
170    _EGLThreadInfo *t = _eglCheckedGetTSD();
171    if (!t) {
172       t = _eglCreateThreadInfo();
173       _eglSetTSD(t);
174    }
175 
176    return t;
177 }
178 
179 
180 /**
181  * Destroy the calling thread's thread info.
182  */
183 void
_eglDestroyCurrentThread(void)184 _eglDestroyCurrentThread(void)
185 {
186    _EGLThreadInfo *t = _eglCheckedGetTSD();
187    if (t) {
188       _eglDestroyThreadInfo(t);
189       _eglSetTSD(NULL);
190    }
191 }
192 
193 
194 /**
195  * Return true if the calling thread's thread info is dummy.
196  * A dummy thread info is shared by all threads and should not be modified.
197  * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
198  * before updating the thread info.
199  */
200 EGLBoolean
_eglIsCurrentThreadDummy(void)201 _eglIsCurrentThreadDummy(void)
202 {
203    _EGLThreadInfo *t = _eglCheckedGetTSD();
204    return (!t || t == &dummy_thread);
205 }
206 
207 
208 /**
209  * Return the currently bound context of the current API, or NULL.
210  */
211 _EGLContext *
_eglGetCurrentContext(void)212 _eglGetCurrentContext(void)
213 {
214    _EGLThreadInfo *t = _eglGetCurrentThread();
215    return t->CurrentContext;
216 }
217 
218 
219 /**
220  * Record EGL error code and return EGL_FALSE.
221  */
222 static EGLBoolean
_eglInternalError(EGLint errCode,const char * msg)223 _eglInternalError(EGLint errCode, const char *msg)
224 {
225    _EGLThreadInfo *t = _eglGetCurrentThread();
226 
227    if (t == &dummy_thread)
228       return EGL_FALSE;
229 
230    t->LastError = errCode;
231 
232    if (errCode != EGL_SUCCESS) {
233       const char *s;
234 
235       switch (errCode) {
236       case EGL_BAD_ACCESS:
237          s = "EGL_BAD_ACCESS";
238          break;
239       case EGL_BAD_ALLOC:
240          s = "EGL_BAD_ALLOC";
241          break;
242       case EGL_BAD_ATTRIBUTE:
243          s = "EGL_BAD_ATTRIBUTE";
244          break;
245       case EGL_BAD_CONFIG:
246          s = "EGL_BAD_CONFIG";
247          break;
248       case EGL_BAD_CONTEXT:
249          s = "EGL_BAD_CONTEXT";
250          break;
251       case EGL_BAD_CURRENT_SURFACE:
252          s = "EGL_BAD_CURRENT_SURFACE";
253          break;
254       case EGL_BAD_DISPLAY:
255          s = "EGL_BAD_DISPLAY";
256          break;
257       case EGL_BAD_MATCH:
258          s = "EGL_BAD_MATCH";
259          break;
260       case EGL_BAD_NATIVE_PIXMAP:
261          s = "EGL_BAD_NATIVE_PIXMAP";
262          break;
263       case EGL_BAD_NATIVE_WINDOW:
264          s = "EGL_BAD_NATIVE_WINDOW";
265          break;
266       case EGL_BAD_PARAMETER:
267          s = "EGL_BAD_PARAMETER";
268          break;
269       case EGL_BAD_SURFACE:
270          s = "EGL_BAD_SURFACE";
271          break;
272       case EGL_NOT_INITIALIZED:
273          s = "EGL_NOT_INITIALIZED";
274          break;
275       default:
276          s = "other EGL error";
277       }
278       _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
279    }
280 
281    return EGL_FALSE;
282 }
283 
284 EGLBoolean
_eglError(EGLint errCode,const char * msg)285 _eglError(EGLint errCode, const char *msg)
286 {
287    if (errCode != EGL_SUCCESS) {
288       EGLint type;
289       if (errCode == EGL_BAD_ALLOC)
290          type = EGL_DEBUG_MSG_CRITICAL_KHR;
291       else
292          type = EGL_DEBUG_MSG_ERROR_KHR;
293 
294       _eglDebugReport(errCode, NULL, type, msg);
295    } else
296       _eglInternalError(errCode, msg);
297 
298    return EGL_FALSE;
299 }
300 
301 void
_eglDebugReport(EGLenum error,const char * funcName,EGLint type,const char * message,...)302 _eglDebugReport(EGLenum error, const char *funcName,
303       EGLint type, const char *message, ...)
304 {
305    _EGLThreadInfo *thr = _eglGetCurrentThread();
306    EGLDEBUGPROCKHR callback = NULL;
307    va_list args;
308 
309    if (funcName == NULL)
310       funcName = thr->CurrentFuncName;
311 
312    mtx_lock(_eglGlobal.Mutex);
313    if (_eglGlobal.debugTypesEnabled & DebugBitFromType(type))
314       callback = _eglGlobal.debugCallback;
315 
316    mtx_unlock(_eglGlobal.Mutex);
317 
318    char *message_buf = NULL;
319    if (message != NULL) {
320       va_start(args, message);
321       if (vasprintf(&message_buf, message, args) < 0)
322          message_buf = NULL;
323       va_end(args);
324    }
325 
326    if (callback != NULL) {
327       callback(error, funcName, type, thr->Label, thr->CurrentObjectLabel,
328                message_buf);
329    }
330 
331    if (type == EGL_DEBUG_MSG_CRITICAL_KHR || type == EGL_DEBUG_MSG_ERROR_KHR) {
332       char *func_message_buf = NULL;
333       /* Note: _eglError() is often called with msg == thr->currentFuncName */
334       if (message_buf && funcName && strcmp(message_buf, funcName) != 0) {
335          if (asprintf(&func_message_buf, "%s: %s", funcName, message_buf) < 0)
336             func_message_buf = NULL;
337       }
338       _eglInternalError(error, func_message_buf ? func_message_buf : funcName);
339       free(func_message_buf);
340    }
341    free(message_buf);
342 }
343