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