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 **************************************************************************/
31 #include "c99_compat.h"
35 #include "eglcurrent.h"
36 #include "eglglobals.h"
39 /* This should be kept in sync with _eglInitThreadInfo() */
40 #define _EGL_THREAD_INFO_INITIALIZER \
41 { EGL_SUCCESS, { NULL }, 0 }
43 /* a fallback thread info to guarantee that every thread always has one */
44 static _EGLThreadInfo dummy_thread
= _EGL_THREAD_INFO_INITIALIZER
;
50 static _EGLMutex _egl_TSDMutex
= _EGL_MUTEX_INITIALIZER
;
51 static EGLBoolean _egl_TSDInitialized
;
52 static pthread_key_t _egl_TSD
;
53 static void (*_egl_FreeTSD
)(_EGLThreadInfo
*);
56 static __thread
const _EGLThreadInfo
*_egl_TLS
57 __attribute__ ((tls_model("initial-exec")));
60 static inline void _eglSetTSD(const _EGLThreadInfo
*t
)
62 pthread_setspecific(_egl_TSD
, (const void *) t
);
68 static inline _EGLThreadInfo
*_eglGetTSD(void)
71 return (_EGLThreadInfo
*) _egl_TLS
;
73 return (_EGLThreadInfo
*) pthread_getspecific(_egl_TSD
);
77 static inline void _eglFiniTSD(void)
79 _eglLockMutex(&_egl_TSDMutex
);
80 if (_egl_TSDInitialized
) {
81 _EGLThreadInfo
*t
= _eglGetTSD();
83 _egl_TSDInitialized
= EGL_FALSE
;
84 if (t
&& _egl_FreeTSD
)
85 _egl_FreeTSD((void *) t
);
86 pthread_key_delete(_egl_TSD
);
88 _eglUnlockMutex(&_egl_TSDMutex
);
91 static inline EGLBoolean
_eglInitTSD(void (*dtor
)(_EGLThreadInfo
*))
93 if (!_egl_TSDInitialized
) {
94 _eglLockMutex(&_egl_TSDMutex
);
96 /* check again after acquiring lock */
97 if (!_egl_TSDInitialized
) {
98 if (pthread_key_create(&_egl_TSD
, (void (*)(void *)) dtor
) != 0) {
99 _eglUnlockMutex(&_egl_TSDMutex
);
103 _eglAddAtExitCall(_eglFiniTSD
);
104 _egl_TSDInitialized
= EGL_TRUE
;
107 _eglUnlockMutex(&_egl_TSDMutex
);
113 #else /* HAVE_PTHREAD */
114 static const _EGLThreadInfo
*_egl_TSD
;
115 static void (*_egl_FreeTSD
)(_EGLThreadInfo
*);
117 static inline void _eglSetTSD(const _EGLThreadInfo
*t
)
122 static inline _EGLThreadInfo
*_eglGetTSD(void)
124 return (_EGLThreadInfo
*) _egl_TSD
;
127 static inline void _eglFiniTSD(void)
129 if (_egl_FreeTSD
&& _egl_TSD
)
130 _egl_FreeTSD((_EGLThreadInfo
*) _egl_TSD
);
133 static inline EGLBoolean
_eglInitTSD(void (*dtor
)(_EGLThreadInfo
*))
135 if (!_egl_FreeTSD
&& dtor
) {
137 _eglAddAtExitCall(_eglFiniTSD
);
142 #endif /* !HAVE_PTHREAD */
146 _eglInitThreadInfo(_EGLThreadInfo
*t
)
148 memset(t
, 0, sizeof(*t
));
149 t
->LastError
= EGL_SUCCESS
;
150 /* default, per EGL spec */
151 t
->CurrentAPIIndex
= _eglConvertApiToIndex(EGL_OPENGL_ES_API
);
156 * Allocate and init a new _EGLThreadInfo object.
158 static _EGLThreadInfo
*
159 _eglCreateThreadInfo(void)
161 _EGLThreadInfo
*t
= calloc(1, sizeof(_EGLThreadInfo
));
163 _eglInitThreadInfo(t
);
171 * Delete/free a _EGLThreadInfo object.
174 _eglDestroyThreadInfo(_EGLThreadInfo
*t
)
176 if (t
!= &dummy_thread
)
182 * Make sure TSD is initialized and return current value.
184 static inline _EGLThreadInfo
*
185 _eglCheckedGetTSD(void)
187 if (_eglInitTSD(&_eglDestroyThreadInfo
) != EGL_TRUE
) {
188 _eglLog(_EGL_FATAL
, "failed to initialize \"current\" system");
197 * Return the calling thread's thread info.
198 * If the calling thread nevers calls this function before, or if its thread
199 * info was destroyed, a new one is created. This function never returns NULL.
200 * In the case allocation fails, a dummy one is returned. See also
201 * _eglIsCurrentThreadDummy.
204 _eglGetCurrentThread(void)
206 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
208 t
= _eglCreateThreadInfo();
217 * Destroy the calling thread's thread info.
220 _eglDestroyCurrentThread(void)
222 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
224 _eglDestroyThreadInfo(t
);
231 * Return true if the calling thread's thread info is dummy.
232 * A dummy thread info is shared by all threads and should not be modified.
233 * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
234 * before updating the thread info.
237 _eglIsCurrentThreadDummy(void)
239 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
240 return (!t
|| t
== &dummy_thread
);
245 * Return the currently bound context of the given API, or NULL.
248 _eglGetAPIContext(EGLenum api
)
250 _EGLThreadInfo
*t
= _eglGetCurrentThread();
251 return t
->CurrentContexts
[_eglConvertApiToIndex(api
)];
256 * Return the currently bound context of the current API, or NULL.
259 _eglGetCurrentContext(void)
261 _EGLThreadInfo
*t
= _eglGetCurrentThread();
262 return t
->CurrentContexts
[t
->CurrentAPIIndex
];
267 * Record EGL error code and return EGL_FALSE.
270 _eglError(EGLint errCode
, const char *msg
)
272 _EGLThreadInfo
*t
= _eglGetCurrentThread();
274 if (t
== &dummy_thread
)
277 t
->LastError
= errCode
;
279 if (errCode
!= EGL_SUCCESS
) {
284 s
= "EGL_BAD_ACCESS";
289 case EGL_BAD_ATTRIBUTE
:
290 s
= "EGL_BAD_ATTRIBUTE";
293 s
= "EGL_BAD_CONFIG";
295 case EGL_BAD_CONTEXT
:
296 s
= "EGL_BAD_CONTEXT";
298 case EGL_BAD_CURRENT_SURFACE
:
299 s
= "EGL_BAD_CURRENT_SURFACE";
301 case EGL_BAD_DISPLAY
:
302 s
= "EGL_BAD_DISPLAY";
307 case EGL_BAD_NATIVE_PIXMAP
:
308 s
= "EGL_BAD_NATIVE_PIXMAP";
310 case EGL_BAD_NATIVE_WINDOW
:
311 s
= "EGL_BAD_NATIVE_WINDOW";
313 case EGL_BAD_PARAMETER
:
314 s
= "EGL_BAD_PARAMETER";
316 case EGL_BAD_SURFACE
:
317 s
= "EGL_BAD_SURFACE";
319 case EGL_NOT_INITIALIZED
:
320 s
= "EGL_NOT_INITIALIZED";
322 #ifdef EGL_MESA_screen_surface
323 case EGL_BAD_SCREEN_MESA
:
324 s
= "EGL_BAD_SCREEN_MESA";
326 case EGL_BAD_MODE_MESA
:
327 s
= "EGL_BAD_MODE_MESA";
331 s
= "other EGL error";
333 _eglLog(_EGL_DEBUG
, "EGL user error 0x%x (%s) in %s\n", errCode
, s
, msg
);