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 (*_egl_FreeTSD
)(_EGLThreadInfo
*);
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 if (t
&& _egl_FreeTSD
)
77 _egl_FreeTSD((void *) t
);
80 mtx_unlock(&_egl_TSDMutex
);
83 static inline EGLBoolean
_eglInitTSD(void (*dtor
)(_EGLThreadInfo
*))
85 if (!_egl_TSDInitialized
) {
86 mtx_lock(&_egl_TSDMutex
);
88 /* check again after acquiring lock */
89 if (!_egl_TSDInitialized
) {
90 if (tss_create(&_egl_TSD
, (void (*)(void *)) dtor
) != thrd_success
) {
91 mtx_unlock(&_egl_TSDMutex
);
95 _eglAddAtExitCall(_eglFiniTSD
);
96 _egl_TSDInitialized
= EGL_TRUE
;
99 mtx_unlock(&_egl_TSDMutex
);
106 _eglInitThreadInfo(_EGLThreadInfo
*t
)
108 t
->LastError
= EGL_SUCCESS
;
109 /* default, per EGL spec */
110 t
->CurrentAPI
= EGL_OPENGL_ES_API
;
115 * Allocate and init a new _EGLThreadInfo object.
117 static _EGLThreadInfo
*
118 _eglCreateThreadInfo(void)
120 _EGLThreadInfo
*t
= calloc(1, sizeof(_EGLThreadInfo
));
124 _eglInitThreadInfo(t
);
130 * Delete/free a _EGLThreadInfo object.
133 _eglDestroyThreadInfo(_EGLThreadInfo
*t
)
135 if (t
!= &dummy_thread
)
141 * Make sure TSD is initialized and return current value.
143 static inline _EGLThreadInfo
*
144 _eglCheckedGetTSD(void)
146 if (_eglInitTSD(&_eglDestroyThreadInfo
) != EGL_TRUE
) {
147 _eglLog(_EGL_FATAL
, "failed to initialize \"current\" system");
156 * Return the calling thread's thread info.
157 * If the calling thread nevers calls this function before, or if its thread
158 * info was destroyed, a new one is created. This function never returns NULL.
159 * In the case allocation fails, a dummy one is returned. See also
160 * _eglIsCurrentThreadDummy.
163 _eglGetCurrentThread(void)
165 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
167 t
= _eglCreateThreadInfo();
176 * Destroy the calling thread's thread info.
179 _eglDestroyCurrentThread(void)
181 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
183 _eglDestroyThreadInfo(t
);
190 * Return true if the calling thread's thread info is dummy.
191 * A dummy thread info is shared by all threads and should not be modified.
192 * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
193 * before updating the thread info.
196 _eglIsCurrentThreadDummy(void)
198 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
199 return (!t
|| t
== &dummy_thread
);
204 * Return the currently bound context of the current API, or NULL.
207 _eglGetCurrentContext(void)
209 _EGLThreadInfo
*t
= _eglGetCurrentThread();
210 return t
->CurrentContext
;
215 * Record EGL error code and return EGL_FALSE.
218 _eglInternalError(EGLint errCode
, const char *msg
)
220 _EGLThreadInfo
*t
= _eglGetCurrentThread();
222 if (t
== &dummy_thread
)
225 t
->LastError
= errCode
;
227 if (errCode
!= EGL_SUCCESS
) {
232 s
= "EGL_BAD_ACCESS";
237 case EGL_BAD_ATTRIBUTE
:
238 s
= "EGL_BAD_ATTRIBUTE";
241 s
= "EGL_BAD_CONFIG";
243 case EGL_BAD_CONTEXT
:
244 s
= "EGL_BAD_CONTEXT";
246 case EGL_BAD_CURRENT_SURFACE
:
247 s
= "EGL_BAD_CURRENT_SURFACE";
249 case EGL_BAD_DISPLAY
:
250 s
= "EGL_BAD_DISPLAY";
255 case EGL_BAD_NATIVE_PIXMAP
:
256 s
= "EGL_BAD_NATIVE_PIXMAP";
258 case EGL_BAD_NATIVE_WINDOW
:
259 s
= "EGL_BAD_NATIVE_WINDOW";
261 case EGL_BAD_PARAMETER
:
262 s
= "EGL_BAD_PARAMETER";
264 case EGL_BAD_SURFACE
:
265 s
= "EGL_BAD_SURFACE";
267 case EGL_NOT_INITIALIZED
:
268 s
= "EGL_NOT_INITIALIZED";
271 s
= "other EGL error";
273 _eglLog(_EGL_DEBUG
, "EGL user error 0x%x (%s) in %s\n", errCode
, s
, msg
);
280 _eglError(EGLint errCode
, const char *msg
)
282 if (errCode
!= EGL_SUCCESS
) {
284 if (errCode
== EGL_BAD_ALLOC
) {
285 type
= EGL_DEBUG_MSG_CRITICAL_KHR
;
287 type
= EGL_DEBUG_MSG_ERROR_KHR
;
290 _eglDebugReport(errCode
, msg
, type
, NULL
);
292 _eglInternalError(errCode
, msg
);
298 * Returns the label set for the current thread.
301 _eglGetThreadLabel(void)
303 _EGLThreadInfo
*t
= _eglGetCurrentThread();
308 _eglDebugReportFullv(EGLenum error
, const char *command
, const char *funcName
,
309 EGLint type
, EGLLabelKHR objectLabel
, const char *message
, va_list args
)
311 EGLDEBUGPROCKHR callback
= NULL
;
313 mtx_lock(_eglGlobal
.Mutex
);
314 if (_eglGlobal
.debugTypesEnabled
& DebugBitFromType(type
)) {
315 callback
= _eglGlobal
.debugCallback
;
317 mtx_unlock(_eglGlobal
.Mutex
);
319 if (callback
!= NULL
) {
322 if (message
!= NULL
) {
323 if (vasprintf(&buf
, message
, args
) < 0) {
327 callback(error
, command
, type
, _eglGetThreadLabel(), objectLabel
, buf
);
331 if (type
== EGL_DEBUG_MSG_CRITICAL_KHR
|| type
== EGL_DEBUG_MSG_ERROR_KHR
) {
332 _eglInternalError(error
, funcName
);
337 _eglDebugReportFull(EGLenum error
, const char *command
, const char *funcName
,
338 EGLint type
, EGLLabelKHR objectLabel
, const char *message
, ...)
341 va_start(args
, message
);
342 _eglDebugReportFullv(error
, command
, funcName
, type
, objectLabel
, message
, args
);
347 _eglDebugReport(EGLenum error
, const char *funcName
,
348 EGLint type
, const char *message
, ...)
350 _EGLThreadInfo
*thr
= _eglGetCurrentThread();
353 if (funcName
== NULL
) {
354 funcName
= thr
->CurrentFuncName
;
357 va_start(args
, message
);
358 _eglDebugReportFullv(error
, thr
->CurrentFuncName
, funcName
, type
, thr
->CurrentObjectLabel
, message
, args
);