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"
32 #include "c11/threads.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
;
45 static mtx_t _egl_TSDMutex
= _MTX_INITIALIZER_NP
;
46 static EGLBoolean _egl_TSDInitialized
;
47 static tss_t _egl_TSD
;
48 static void (*_egl_FreeTSD
)(_EGLThreadInfo
*);
51 static __thread
const _EGLThreadInfo
*_egl_TLS
52 __attribute__ ((tls_model("initial-exec")));
55 static inline void _eglSetTSD(const _EGLThreadInfo
*t
)
57 tss_set(_egl_TSD
, (const void *) t
);
63 static inline _EGLThreadInfo
*_eglGetTSD(void)
66 return (_EGLThreadInfo
*) _egl_TLS
;
68 return (_EGLThreadInfo
*) tss_get(_egl_TSD
);
72 static inline void _eglFiniTSD(void)
74 mtx_lock(&_egl_TSDMutex
);
75 if (_egl_TSDInitialized
) {
76 _EGLThreadInfo
*t
= _eglGetTSD();
78 _egl_TSDInitialized
= EGL_FALSE
;
79 if (t
&& _egl_FreeTSD
)
80 _egl_FreeTSD((void *) t
);
83 mtx_unlock(&_egl_TSDMutex
);
86 static inline EGLBoolean
_eglInitTSD(void (*dtor
)(_EGLThreadInfo
*))
88 if (!_egl_TSDInitialized
) {
89 mtx_lock(&_egl_TSDMutex
);
91 /* check again after acquiring lock */
92 if (!_egl_TSDInitialized
) {
93 if (tss_create(&_egl_TSD
, (void (*)(void *)) dtor
) != thrd_success
) {
94 mtx_unlock(&_egl_TSDMutex
);
98 _eglAddAtExitCall(_eglFiniTSD
);
99 _egl_TSDInitialized
= EGL_TRUE
;
102 mtx_unlock(&_egl_TSDMutex
);
109 _eglInitThreadInfo(_EGLThreadInfo
*t
)
111 memset(t
, 0, sizeof(*t
));
112 t
->LastError
= EGL_SUCCESS
;
113 /* default, per EGL spec */
114 t
->CurrentAPIIndex
= _eglConvertApiToIndex(EGL_OPENGL_ES_API
);
119 * Allocate and init a new _EGLThreadInfo object.
121 static _EGLThreadInfo
*
122 _eglCreateThreadInfo(void)
124 _EGLThreadInfo
*t
= calloc(1, sizeof(_EGLThreadInfo
));
126 _eglInitThreadInfo(t
);
134 * Delete/free a _EGLThreadInfo object.
137 _eglDestroyThreadInfo(_EGLThreadInfo
*t
)
139 if (t
!= &dummy_thread
)
145 * Make sure TSD is initialized and return current value.
147 static inline _EGLThreadInfo
*
148 _eglCheckedGetTSD(void)
150 if (_eglInitTSD(&_eglDestroyThreadInfo
) != EGL_TRUE
) {
151 _eglLog(_EGL_FATAL
, "failed to initialize \"current\" system");
160 * Return the calling thread's thread info.
161 * If the calling thread nevers calls this function before, or if its thread
162 * info was destroyed, a new one is created. This function never returns NULL.
163 * In the case allocation fails, a dummy one is returned. See also
164 * _eglIsCurrentThreadDummy.
167 _eglGetCurrentThread(void)
169 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
171 t
= _eglCreateThreadInfo();
180 * Destroy the calling thread's thread info.
183 _eglDestroyCurrentThread(void)
185 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
187 _eglDestroyThreadInfo(t
);
194 * Return true if the calling thread's thread info is dummy.
195 * A dummy thread info is shared by all threads and should not be modified.
196 * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness
197 * before updating the thread info.
200 _eglIsCurrentThreadDummy(void)
202 _EGLThreadInfo
*t
= _eglCheckedGetTSD();
203 return (!t
|| t
== &dummy_thread
);
208 * Return the currently bound context of the given API, or NULL.
211 _eglGetAPIContext(EGLenum api
)
213 _EGLThreadInfo
*t
= _eglGetCurrentThread();
214 return t
->CurrentContexts
[_eglConvertApiToIndex(api
)];
219 * Return the currently bound context of the current API, or NULL.
222 _eglGetCurrentContext(void)
224 _EGLThreadInfo
*t
= _eglGetCurrentThread();
225 return t
->CurrentContexts
[t
->CurrentAPIIndex
];
230 * Record EGL error code and return EGL_FALSE.
233 _eglError(EGLint errCode
, const char *msg
)
235 _EGLThreadInfo
*t
= _eglGetCurrentThread();
237 if (t
== &dummy_thread
)
240 t
->LastError
= errCode
;
242 if (errCode
!= EGL_SUCCESS
) {
247 s
= "EGL_BAD_ACCESS";
252 case EGL_BAD_ATTRIBUTE
:
253 s
= "EGL_BAD_ATTRIBUTE";
256 s
= "EGL_BAD_CONFIG";
258 case EGL_BAD_CONTEXT
:
259 s
= "EGL_BAD_CONTEXT";
261 case EGL_BAD_CURRENT_SURFACE
:
262 s
= "EGL_BAD_CURRENT_SURFACE";
264 case EGL_BAD_DISPLAY
:
265 s
= "EGL_BAD_DISPLAY";
270 case EGL_BAD_NATIVE_PIXMAP
:
271 s
= "EGL_BAD_NATIVE_PIXMAP";
273 case EGL_BAD_NATIVE_WINDOW
:
274 s
= "EGL_BAD_NATIVE_WINDOW";
276 case EGL_BAD_PARAMETER
:
277 s
= "EGL_BAD_PARAMETER";
279 case EGL_BAD_SURFACE
:
280 s
= "EGL_BAD_SURFACE";
282 case EGL_NOT_INITIALIZED
:
283 s
= "EGL_NOT_INITIALIZED";
285 #ifdef EGL_MESA_screen_surface
286 case EGL_BAD_SCREEN_MESA
:
287 s
= "EGL_BAD_SCREEN_MESA";
289 case EGL_BAD_MODE_MESA
:
290 s
= "EGL_BAD_MODE_MESA";
294 s
= "other EGL error";
296 _eglLog(_EGL_DEBUG
, "EGL user error 0x%x (%s) in %s\n", errCode
, s
, msg
);