1 /**************************************************************************
3 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
33 #include "c99_compat.h"
34 #include "c11/threads.h"
37 #include "eglcurrent.h"
38 #include "eglglobals.h"
40 /* a fallback thread info to guarantee that every thread always has one */
41 static _EGLThreadInfo dummy_thread
;
42 static mtx_t _egl_TSDMutex
= _MTX_INITIALIZER_NP
;
43 static EGLBoolean _egl_TSDInitialized
;
44 static tss_t _egl_TSD
;
45 static void _eglDestroyThreadInfo(_EGLThreadInfo
*t
);
48 static __thread
const _EGLThreadInfo
*_egl_TLS
49 __attribute__ ((tls_model("initial-exec")));
52 static inline void _eglSetTSD(const _EGLThreadInfo
*t
)
54 tss_set(_egl_TSD
, (void *) t
);
60 static inline _EGLThreadInfo
*_eglGetTSD(void)
63 return (_EGLThreadInfo
*) _egl_TLS
;
65 return (_EGLThreadInfo
*) tss_get(_egl_TSD
);
69 static inline void _eglFiniTSD(void)
71 mtx_lock(&_egl_TSDMutex
);
72 if (_egl_TSDInitialized
) {
73 _EGLThreadInfo
*t
= _eglGetTSD();
75 _egl_TSDInitialized
= EGL_FALSE
;
76 _eglDestroyThreadInfo(t
);
79 mtx_unlock(&_egl_TSDMutex
);
82 static inline EGLBoolean
_eglInitTSD()
84 if (!_egl_TSDInitialized
) {
85 mtx_lock(&_egl_TSDMutex
);
87 /* check again after acquiring lock */
88 if (!_egl_TSDInitialized
) {
89 if (tss_create(&_egl_TSD
, (void (*)(void *)) _eglDestroyThreadInfo
) != thrd_success
) {
90 mtx_unlock(&_egl_TSDMutex
);
93 _eglAddAtExitCall(_eglFiniTSD
);
94 _egl_TSDInitialized
= EGL_TRUE
;
97 mtx_unlock(&_egl_TSDMutex
);
104 _eglInitThreadInfo(_EGLThreadInfo
*t
)
106 t
->LastError
= EGL_SUCCESS
;
107 /* default, per EGL spec */
108 t
->CurrentAPI
= EGL_OPENGL_ES_API
;
113 * Allocate and init a new _EGLThreadInfo object.
115 static _EGLThreadInfo
*
116 _eglCreateThreadInfo(void)
118 _EGLThreadInfo
*t
= calloc(1, sizeof(_EGLThreadInfo
));
122 _eglInitThreadInfo(t
);
128 * Delete/free a _EGLThreadInfo object.
131 _eglDestroyThreadInfo(_EGLThreadInfo
*t
)
133 if (t
!= &dummy_thread
)
139 * Make sure TSD is initialized and return current value.
141 static inline _EGLThreadInfo
*
142 _eglCheckedGetTSD(void)
144 if (_eglInitTSD() != EGL_TRUE
) {
145 _eglLog(_EGL_FATAL
, "failed to initialize \"current\" system");
154 * Return the calling thread's thread info.
155 * If the calling thread nevers calls this function before, or if its thread
156 * info was destroyed, a new one is created. This function never returns NULL.
157 * In the case allocation fails, a dummy one is returned. See also
158 * _eglIsCurrentThreadDummy.
161 _eglGetCurrentThread(void)
163 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
165 t
= _eglCreateThreadInfo();
174 * Destroy the calling thread's thread info.
177 _eglDestroyCurrentThread(void)
179 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
181 _eglDestroyThreadInfo(t
);
188 * Return true if the calling thread's thread info is dummy.
189 * A dummy thread info is shared by all threads and should not be modified.
190 * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
191 * before updating the thread info.
194 _eglIsCurrentThreadDummy(void)
196 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
197 return (!t
|| t
== &dummy_thread
);
202 * Return the currently bound context of the current API, or NULL.
205 _eglGetCurrentContext(void)
207 _EGLThreadInfo
*t
= _eglGetCurrentThread();
208 return t
->CurrentContext
;
213 * Record EGL error code and return EGL_FALSE.
216 _eglInternalError(EGLint errCode
, const char *msg
)
218 _EGLThreadInfo
*t
= _eglGetCurrentThread();
220 if (t
== &dummy_thread
)
223 t
->LastError
= errCode
;
225 if (errCode
!= EGL_SUCCESS
) {
230 s
= "EGL_BAD_ACCESS";
235 case EGL_BAD_ATTRIBUTE
:
236 s
= "EGL_BAD_ATTRIBUTE";
239 s
= "EGL_BAD_CONFIG";
241 case EGL_BAD_CONTEXT
:
242 s
= "EGL_BAD_CONTEXT";
244 case EGL_BAD_CURRENT_SURFACE
:
245 s
= "EGL_BAD_CURRENT_SURFACE";
247 case EGL_BAD_DISPLAY
:
248 s
= "EGL_BAD_DISPLAY";
253 case EGL_BAD_NATIVE_PIXMAP
:
254 s
= "EGL_BAD_NATIVE_PIXMAP";
256 case EGL_BAD_NATIVE_WINDOW
:
257 s
= "EGL_BAD_NATIVE_WINDOW";
259 case EGL_BAD_PARAMETER
:
260 s
= "EGL_BAD_PARAMETER";
262 case EGL_BAD_SURFACE
:
263 s
= "EGL_BAD_SURFACE";
265 case EGL_NOT_INITIALIZED
:
266 s
= "EGL_NOT_INITIALIZED";
269 s
= "other EGL error";
271 _eglLog(_EGL_DEBUG
, "EGL user error 0x%x (%s) in %s\n", errCode
, s
, msg
);
278 _eglError(EGLint errCode
, const char *msg
)
280 if (errCode
!= EGL_SUCCESS
) {
282 if (errCode
== EGL_BAD_ALLOC
)
283 type
= EGL_DEBUG_MSG_CRITICAL_KHR
;
285 type
= EGL_DEBUG_MSG_ERROR_KHR
;
287 _eglDebugReport(errCode
, NULL
, type
, msg
);
289 _eglInternalError(errCode
, msg
);
295 _eglDebugReport(EGLenum error
, const char *funcName
,
296 EGLint type
, const char *message
, ...)
298 _EGLThreadInfo
*thr
= _eglGetCurrentThread();
299 EGLDEBUGPROCKHR callback
= NULL
;
302 if (funcName
== NULL
)
303 funcName
= thr
->CurrentFuncName
;
305 mtx_lock(_eglGlobal
.Mutex
);
306 if (_eglGlobal
.debugTypesEnabled
& DebugBitFromType(type
))
307 callback
= _eglGlobal
.debugCallback
;
309 mtx_unlock(_eglGlobal
.Mutex
);
311 char *message_buf
= NULL
;
312 if (message
!= NULL
) {
313 va_start(args
, message
);
314 if (vasprintf(&message_buf
, message
, args
) < 0)
319 if (callback
!= NULL
) {
320 callback(error
, funcName
, type
, thr
->Label
, thr
->CurrentObjectLabel
,
324 if (type
== EGL_DEBUG_MSG_CRITICAL_KHR
|| type
== EGL_DEBUG_MSG_ERROR_KHR
) {
325 char *func_message_buf
= NULL
;
326 /* Note: _eglError() is often called with msg == thr->currentFuncName */
327 if (message_buf
&& funcName
&& strcmp(message_buf
, funcName
) != 0) {
328 if (asprintf(&func_message_buf
, "%s: %s", funcName
, message_buf
) < 0)
329 func_message_buf
= NULL
;
331 _eglInternalError(error
, func_message_buf
? func_message_buf
: funcName
);
332 free(func_message_buf
);