egl/main: replace INLINE with inline
[mesa.git] / src / egl / main / eglcurrent.c
1 /**************************************************************************
2 *
3 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
4 * All Rights Reserved.
5 *
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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
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.
25 *
26 **************************************************************************/
27
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include "c99_compat.h"
32
33 #include "egllog.h"
34 #include "eglmutex.h"
35 #include "eglcurrent.h"
36 #include "eglglobals.h"
37
38
39 /* This should be kept in sync with _eglInitThreadInfo() */
40 #define _EGL_THREAD_INFO_INITIALIZER \
41 { EGL_SUCCESS, { NULL }, 0 }
42
43 /* a fallback thread info to guarantee that every thread always has one */
44 static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
45
46
47 #if HAVE_PTHREAD
48 #include <pthread.h>
49
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 *);
54
55 #ifdef GLX_USE_TLS
56 static __thread const _EGLThreadInfo *_egl_TLS
57 __attribute__ ((tls_model("initial-exec")));
58 #endif
59
60 static inline void _eglSetTSD(const _EGLThreadInfo *t)
61 {
62 pthread_setspecific(_egl_TSD, (const void *) t);
63 #ifdef GLX_USE_TLS
64 _egl_TLS = t;
65 #endif
66 }
67
68 static inline _EGLThreadInfo *_eglGetTSD(void)
69 {
70 #ifdef GLX_USE_TLS
71 return (_EGLThreadInfo *) _egl_TLS;
72 #else
73 return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD);
74 #endif
75 }
76
77 static inline void _eglFiniTSD(void)
78 {
79 _eglLockMutex(&_egl_TSDMutex);
80 if (_egl_TSDInitialized) {
81 _EGLThreadInfo *t = _eglGetTSD();
82
83 _egl_TSDInitialized = EGL_FALSE;
84 if (t && _egl_FreeTSD)
85 _egl_FreeTSD((void *) t);
86 pthread_key_delete(_egl_TSD);
87 }
88 _eglUnlockMutex(&_egl_TSDMutex);
89 }
90
91 static inline EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
92 {
93 if (!_egl_TSDInitialized) {
94 _eglLockMutex(&_egl_TSDMutex);
95
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);
100 return EGL_FALSE;
101 }
102 _egl_FreeTSD = dtor;
103 _eglAddAtExitCall(_eglFiniTSD);
104 _egl_TSDInitialized = EGL_TRUE;
105 }
106
107 _eglUnlockMutex(&_egl_TSDMutex);
108 }
109
110 return EGL_TRUE;
111 }
112
113 #else /* HAVE_PTHREAD */
114 static const _EGLThreadInfo *_egl_TSD;
115 static void (*_egl_FreeTSD)(_EGLThreadInfo *);
116
117 static inline void _eglSetTSD(const _EGLThreadInfo *t)
118 {
119 _egl_TSD = t;
120 }
121
122 static inline _EGLThreadInfo *_eglGetTSD(void)
123 {
124 return (_EGLThreadInfo *) _egl_TSD;
125 }
126
127 static inline void _eglFiniTSD(void)
128 {
129 if (_egl_FreeTSD && _egl_TSD)
130 _egl_FreeTSD((_EGLThreadInfo *) _egl_TSD);
131 }
132
133 static inline EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
134 {
135 if (!_egl_FreeTSD && dtor) {
136 _egl_FreeTSD = dtor;
137 _eglAddAtExitCall(_eglFiniTSD);
138 }
139 return EGL_TRUE;
140 }
141
142 #endif /* !HAVE_PTHREAD */
143
144
145 static void
146 _eglInitThreadInfo(_EGLThreadInfo *t)
147 {
148 memset(t, 0, sizeof(*t));
149 t->LastError = EGL_SUCCESS;
150 /* default, per EGL spec */
151 t->CurrentAPIIndex = _eglConvertApiToIndex(EGL_OPENGL_ES_API);
152 }
153
154
155 /**
156 * Allocate and init a new _EGLThreadInfo object.
157 */
158 static _EGLThreadInfo *
159 _eglCreateThreadInfo(void)
160 {
161 _EGLThreadInfo *t = calloc(1, sizeof(_EGLThreadInfo));
162 if (t)
163 _eglInitThreadInfo(t);
164 else
165 t = &dummy_thread;
166 return t;
167 }
168
169
170 /**
171 * Delete/free a _EGLThreadInfo object.
172 */
173 static void
174 _eglDestroyThreadInfo(_EGLThreadInfo *t)
175 {
176 if (t != &dummy_thread)
177 free(t);
178 }
179
180
181 /**
182 * Make sure TSD is initialized and return current value.
183 */
184 static inline _EGLThreadInfo *
185 _eglCheckedGetTSD(void)
186 {
187 if (_eglInitTSD(&_eglDestroyThreadInfo) != EGL_TRUE) {
188 _eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
189 return NULL;
190 }
191
192 return _eglGetTSD();
193 }
194
195
196 /**
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.
202 */
203 _EGLThreadInfo *
204 _eglGetCurrentThread(void)
205 {
206 _EGLThreadInfo *t = _eglCheckedGetTSD();
207 if (!t) {
208 t = _eglCreateThreadInfo();
209 _eglSetTSD(t);
210 }
211
212 return t;
213 }
214
215
216 /**
217 * Destroy the calling thread's thread info.
218 */
219 void
220 _eglDestroyCurrentThread(void)
221 {
222 _EGLThreadInfo *t = _eglCheckedGetTSD();
223 if (t) {
224 _eglDestroyThreadInfo(t);
225 _eglSetTSD(NULL);
226 }
227 }
228
229
230 /**
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.
235 */
236 EGLBoolean
237 _eglIsCurrentThreadDummy(void)
238 {
239 _EGLThreadInfo *t = _eglCheckedGetTSD();
240 return (!t || t == &dummy_thread);
241 }
242
243
244 /**
245 * Return the currently bound context of the given API, or NULL.
246 */
247 PUBLIC _EGLContext *
248 _eglGetAPIContext(EGLenum api)
249 {
250 _EGLThreadInfo *t = _eglGetCurrentThread();
251 return t->CurrentContexts[_eglConvertApiToIndex(api)];
252 }
253
254
255 /**
256 * Return the currently bound context of the current API, or NULL.
257 */
258 _EGLContext *
259 _eglGetCurrentContext(void)
260 {
261 _EGLThreadInfo *t = _eglGetCurrentThread();
262 return t->CurrentContexts[t->CurrentAPIIndex];
263 }
264
265
266 /**
267 * Record EGL error code and return EGL_FALSE.
268 */
269 EGLBoolean
270 _eglError(EGLint errCode, const char *msg)
271 {
272 _EGLThreadInfo *t = _eglGetCurrentThread();
273
274 if (t == &dummy_thread)
275 return EGL_FALSE;
276
277 t->LastError = errCode;
278
279 if (errCode != EGL_SUCCESS) {
280 const char *s;
281
282 switch (errCode) {
283 case EGL_BAD_ACCESS:
284 s = "EGL_BAD_ACCESS";
285 break;
286 case EGL_BAD_ALLOC:
287 s = "EGL_BAD_ALLOC";
288 break;
289 case EGL_BAD_ATTRIBUTE:
290 s = "EGL_BAD_ATTRIBUTE";
291 break;
292 case EGL_BAD_CONFIG:
293 s = "EGL_BAD_CONFIG";
294 break;
295 case EGL_BAD_CONTEXT:
296 s = "EGL_BAD_CONTEXT";
297 break;
298 case EGL_BAD_CURRENT_SURFACE:
299 s = "EGL_BAD_CURRENT_SURFACE";
300 break;
301 case EGL_BAD_DISPLAY:
302 s = "EGL_BAD_DISPLAY";
303 break;
304 case EGL_BAD_MATCH:
305 s = "EGL_BAD_MATCH";
306 break;
307 case EGL_BAD_NATIVE_PIXMAP:
308 s = "EGL_BAD_NATIVE_PIXMAP";
309 break;
310 case EGL_BAD_NATIVE_WINDOW:
311 s = "EGL_BAD_NATIVE_WINDOW";
312 break;
313 case EGL_BAD_PARAMETER:
314 s = "EGL_BAD_PARAMETER";
315 break;
316 case EGL_BAD_SURFACE:
317 s = "EGL_BAD_SURFACE";
318 break;
319 case EGL_NOT_INITIALIZED:
320 s = "EGL_NOT_INITIALIZED";
321 break;
322 #ifdef EGL_MESA_screen_surface
323 case EGL_BAD_SCREEN_MESA:
324 s = "EGL_BAD_SCREEN_MESA";
325 break;
326 case EGL_BAD_MODE_MESA:
327 s = "EGL_BAD_MODE_MESA";
328 break;
329 #endif
330 default:
331 s = "other EGL error";
332 }
333 _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
334 }
335
336 return EGL_FALSE;
337 }