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