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 "eglcurrent.h"
34 #include "eglglobals.h"
37 /* This should be kept in sync with _eglInitThreadInfo() */
38 #define _EGL_THREAD_INFO_INITIALIZER \
39 { EGL_SUCCESS, { NULL }, 0 }
41 /* a fallback thread info to guarantee that every thread always has one */
42 static _EGLThreadInfo dummy_thread
= _EGL_THREAD_INFO_INITIALIZER
;
48 static _EGL_DECLARE_MUTEX(_egl_TSDMutex
);
49 static EGLBoolean _egl_TSDInitialized
;
50 static pthread_key_t _egl_TSD
;
51 static void (*_egl_FreeTSD
)(_EGLThreadInfo
*);
54 static __thread
const _EGLThreadInfo
*_egl_TLS
55 __attribute__ ((tls_model("initial-exec")));
58 static INLINE
void _eglSetTSD(const _EGLThreadInfo
*t
)
60 pthread_setspecific(_egl_TSD
, (const void *) t
);
66 static INLINE _EGLThreadInfo
*_eglGetTSD(void)
69 return (_EGLThreadInfo
*) _egl_TLS
;
71 return (_EGLThreadInfo
*) pthread_getspecific(_egl_TSD
);
75 static INLINE
void _eglFiniTSD(void)
77 _eglLockMutex(&_egl_TSDMutex
);
78 if (_egl_TSDInitialized
) {
79 _EGLThreadInfo
*t
= _eglGetTSD();
81 _egl_TSDInitialized
= EGL_FALSE
;
82 if (t
&& _egl_FreeTSD
)
83 _egl_FreeTSD((void *) t
);
84 pthread_key_delete(_egl_TSD
);
86 _eglUnlockMutex(&_egl_TSDMutex
);
89 static INLINE EGLBoolean
_eglInitTSD(void (*dtor
)(_EGLThreadInfo
*))
91 if (!_egl_TSDInitialized
) {
92 _eglLockMutex(&_egl_TSDMutex
);
94 /* check again after acquiring lock */
95 if (!_egl_TSDInitialized
) {
96 if (pthread_key_create(&_egl_TSD
, (void (*)(void *)) dtor
) != 0) {
97 _eglUnlockMutex(&_egl_TSDMutex
);
101 _eglAddAtExitCall(_eglFiniTSD
);
102 _egl_TSDInitialized
= EGL_TRUE
;
105 _eglUnlockMutex(&_egl_TSDMutex
);
111 #elif defined(_EGL_OS_AROS)
113 #include "aros/tls.h"
115 static struct TaskLocalStorage
* tls
= NULL
;
116 static void (*_egl_FreeTSD
)(_EGLThreadInfo
*);
118 static INLINE
void _eglFiniTSD(void)
123 static INLINE
void _eglSetTSD(const _EGLThreadInfo
*t
)
125 InsertIntoTLS(tls
, (APTR
)t
);
128 static INLINE _EGLThreadInfo
*_eglGetTSD(void)
130 return (_EGLThreadInfo
*)GetFromTLS(tls
);
133 static INLINE EGLBoolean
_eglInitTSD(void (*dtor
)(_EGLThreadInfo
*))
139 _eglAddAtExitCall(_eglFiniTSD
);
148 #include <aros/symbolsets.h>
150 static VOID
_egl_FreeTSD_fn()
152 _EGLThreadInfo
*t
= NULL
;
158 if (t
&& _egl_FreeTSD
)
159 _egl_FreeTSD((void *) t
);
162 ADD2CLOSELIB(_egl_FreeTSD_fn
, 10)
165 static const _EGLThreadInfo
*_egl_TSD
;
166 static void (*_egl_FreeTSD
)(_EGLThreadInfo
*);
168 static INLINE
void _eglSetTSD(const _EGLThreadInfo
*t
)
173 static INLINE _EGLThreadInfo
*_eglGetTSD(void)
175 return (_EGLThreadInfo
*) _egl_TSD
;
178 static INLINE
void _eglFiniTSD(void)
180 if (_egl_FreeTSD
&& _egl_TSD
)
181 _egl_FreeTSD((_EGLThreadInfo
*) _egl_TSD
);
184 static INLINE EGLBoolean
_eglInitTSD(void (*dtor
)(_EGLThreadInfo
*))
186 if (!_egl_FreeTSD
&& dtor
) {
188 _eglAddAtExitCall(_eglFiniTSD
);
193 #endif /* !PTHREADS */
197 _eglInitThreadInfo(_EGLThreadInfo
*t
)
199 memset(t
, 0, sizeof(*t
));
200 t
->LastError
= EGL_SUCCESS
;
201 /* default, per EGL spec */
202 t
->CurrentAPIIndex
= _eglConvertApiToIndex(EGL_OPENGL_ES_API
);
207 * Allocate and init a new _EGLThreadInfo object.
209 static _EGLThreadInfo
*
210 _eglCreateThreadInfo(void)
212 _EGLThreadInfo
*t
= (_EGLThreadInfo
*) calloc(1, sizeof(_EGLThreadInfo
));
214 _eglInitThreadInfo(t
);
222 * Delete/free a _EGLThreadInfo object.
225 _eglDestroyThreadInfo(_EGLThreadInfo
*t
)
227 if (t
!= &dummy_thread
)
233 * Make sure TSD is initialized and return current value.
235 static INLINE _EGLThreadInfo
*
236 _eglCheckedGetTSD(void)
238 if (_eglInitTSD(&_eglDestroyThreadInfo
) != EGL_TRUE
) {
239 _eglLog(_EGL_FATAL
, "failed to initialize \"current\" system");
248 * Return the calling thread's thread info.
249 * If the calling thread nevers calls this function before, or if its thread
250 * info was destroyed, a new one is created. This function never returns NULL.
251 * In the case allocation fails, a dummy one is returned. See also
252 * _eglIsCurrentThreadDummy.
255 _eglGetCurrentThread(void)
257 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
259 t
= _eglCreateThreadInfo();
268 * Destroy the calling thread's thread info.
271 _eglDestroyCurrentThread(void)
273 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
275 _eglDestroyThreadInfo(t
);
282 * Return true if the calling thread's thread info is dummy.
283 * A dummy thread info is shared by all threads and should not be modified.
284 * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
285 * before updating the thread info.
288 _eglIsCurrentThreadDummy(void)
290 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
291 return (!t
|| t
== &dummy_thread
);
296 * Return the currently bound context of the given API, or NULL.
299 _eglGetAPIContext(EGLenum api
)
301 _EGLThreadInfo
*t
= _eglGetCurrentThread();
302 return t
->CurrentContexts
[_eglConvertApiToIndex(api
)];
307 * Return the currently bound context of the current API, or NULL.
310 _eglGetCurrentContext(void)
312 _EGLThreadInfo
*t
= _eglGetCurrentThread();
313 return t
->CurrentContexts
[t
->CurrentAPIIndex
];
318 * Record EGL error code and return EGL_FALSE.
321 _eglError(EGLint errCode
, const char *msg
)
323 _EGLThreadInfo
*t
= _eglGetCurrentThread();
325 if (t
== &dummy_thread
)
328 t
->LastError
= errCode
;
330 if (errCode
!= EGL_SUCCESS
) {
335 s
= "EGL_BAD_ACCESS";
340 case EGL_BAD_ATTRIBUTE
:
341 s
= "EGL_BAD_ATTRIBUTE";
344 s
= "EGL_BAD_CONFIG";
346 case EGL_BAD_CONTEXT
:
347 s
= "EGL_BAD_CONTEXT";
349 case EGL_BAD_CURRENT_SURFACE
:
350 s
= "EGL_BAD_CURRENT_SURFACE";
352 case EGL_BAD_DISPLAY
:
353 s
= "EGL_BAD_DISPLAY";
358 case EGL_BAD_NATIVE_PIXMAP
:
359 s
= "EGL_BAD_NATIVE_PIXMAP";
361 case EGL_BAD_NATIVE_WINDOW
:
362 s
= "EGL_BAD_NATIVE_WINDOW";
364 case EGL_BAD_PARAMETER
:
365 s
= "EGL_BAD_PARAMETER";
367 case EGL_BAD_SURFACE
:
368 s
= "EGL_BAD_SURFACE";
370 case EGL_NOT_INITIALIZED
:
371 s
= "EGL_NOT_INITIALIZED";
373 #ifdef EGL_MESA_screen_surface
374 case EGL_BAD_SCREEN_MESA
:
375 s
= "EGL_BAD_SCREEN_MESA";
377 case EGL_BAD_MODE_MESA
:
378 s
= "EGL_BAD_MODE_MESA";
382 s
= "other EGL error";
384 _eglLog(_EGL_DEBUG
, "EGL user error 0x%x (%s) in %s\n", errCode
, s
, msg
);