blob: df506151b587cf98fab6e21a1d4f4ae70370e0d4 [file] [log] [blame]
Brian Paul40fd1012009-07-17 13:36:06 -06001#include <stdlib.h>
2#include <string.h>
3#include "eglcurrent.h"
4#include "eglcontext.h"
5#include "egllog.h"
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +08006#include "eglmutex.h"
Chia-I Wu64e7bb32009-08-10 16:45:12 +08007#include "eglglobals.h"
Brian Paul40fd1012009-07-17 13:36:06 -06008
9
Chia-I Wu56d21192009-08-10 12:46:08 +080010/* This should be kept in sync with _eglInitThreadInfo() */
11#define _EGL_THREAD_INFO_INITIALIZER \
Chia-I Wu310c7682009-08-17 15:53:54 +080012 { EGL_SUCCESS, { NULL }, 0 }
Chia-I Wu56d21192009-08-10 12:46:08 +080013
Brian Paul40fd1012009-07-17 13:36:06 -060014/* a fallback thread info to guarantee that every thread always has one */
Chia-I Wu56d21192009-08-10 12:46:08 +080015static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
Brian Paul40fd1012009-07-17 13:36:06 -060016
17
18#ifdef GLX_USE_TLS
Chia-I Wu29d11502009-10-10 14:39:43 +080019static __thread const _EGLThreadInfo *_egl_TSD
Brian Paul40fd1012009-07-17 13:36:06 -060020 __attribute__ ((tls_model("initial-exec")));
21
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +080022static INLINE void _eglSetTSD(const _EGLThreadInfo *t)
23{
24 _egl_TSD = t;
25}
Brian Paul40fd1012009-07-17 13:36:06 -060026
27static INLINE _EGLThreadInfo *_eglGetTSD(void)
28{
29 return (_EGLThreadInfo *) _egl_TSD;
30}
31
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +080032static INLINE void _eglFiniTSD(void)
33{
34}
35
36static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
37{
38 /* TODO destroy TSD */
39 (void) dtor;
Chia-I Wu56d21192009-08-10 12:46:08 +080040 (void) _eglFiniTSD;
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +080041 return EGL_TRUE;
42}
43
Brian Paul40fd1012009-07-17 13:36:06 -060044#elif PTHREADS
45#include <pthread.h>
46
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +080047static _EGL_DECLARE_MUTEX(_egl_TSDMutex);
48static EGLBoolean _egl_TSDInitialized;
Brian Paul40fd1012009-07-17 13:36:06 -060049static pthread_key_t _egl_TSD;
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +080050static void (*_egl_FreeTSD)(_EGLThreadInfo *);
Brian Paul40fd1012009-07-17 13:36:06 -060051
52static INLINE void _eglSetTSD(const _EGLThreadInfo *t)
53{
54 pthread_setspecific(_egl_TSD, (const void *) t);
55}
56
57static INLINE _EGLThreadInfo *_eglGetTSD(void)
58{
59 return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD);
60}
61
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +080062static 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
76static 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;
Chia-I Wu64e7bb32009-08-10 16:45:12 +080088 _eglAddAtExitCall(_eglFiniTSD);
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +080089 _egl_TSDInitialized = EGL_TRUE;
90 }
91
92 _eglUnlockMutex(&_egl_TSDMutex);
93 }
94
95 return EGL_TRUE;
96}
97
Brian Paul40fd1012009-07-17 13:36:06 -060098#else /* PTHREADS */
99static const _EGLThreadInfo *_egl_TSD;
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +0800100static void (*_egl_FreeTSD)(_EGLThreadInfo *);
Brian Paul40fd1012009-07-17 13:36:06 -0600101
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +0800102static INLINE void _eglSetTSD(const _EGLThreadInfo *t)
103{
104 _egl_TSD = t;
105}
Brian Paul40fd1012009-07-17 13:36:06 -0600106
107static INLINE _EGLThreadInfo *_eglGetTSD(void)
108{
109 return (_EGLThreadInfo *) _egl_TSD;
110}
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +0800111
112static INLINE void _eglFiniTSD(void)
113{
114 if (_egl_FreeTSD && _egl_TSD)
115 _egl_FreeTSD((_EGLThreadInfo *) _egl_TSD);
116}
117
118static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
119{
120 if (!_egl_FreeTSD && dtor) {
121 _egl_FreeTSD = dtor;
Chia-I Wu64e7bb32009-08-10 16:45:12 +0800122 _eglAddAtExitCall(_eglFiniTSD);
Chia-I Wuf6c2f5e2009-08-10 12:20:31 +0800123 }
124 return EGL_TRUE;
125}
126
Brian Paul40fd1012009-07-17 13:36:06 -0600127#endif /* !PTHREADS */
128
129
130static 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 */
143static _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 */
158static void
159_eglDestroyThreadInfo(_EGLThreadInfo *t)
160{
161 if (t != &dummy_thread)
162 free(t);
163}
164
165
166/**
Chia-I Wu56d21192009-08-10 12:46:08 +0800167 * Make sure TSD is initialized and return current value.
Brian Paul40fd1012009-07-17 13:36:06 -0600168 */
Chia-I Wu56d21192009-08-10 12:46:08 +0800169static INLINE _EGLThreadInfo *
170_eglCheckedGetTSD(void)
Brian Paul40fd1012009-07-17 13:36:06 -0600171{
Chia-I Wu56d21192009-08-10 12:46:08 +0800172 if (_eglInitTSD(&_eglDestroyThreadInfo) != EGL_TRUE) {
173 _eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
174 return NULL;
175 }
Brian Paul40fd1012009-07-17 13:36:06 -0600176
Chia-I Wu56d21192009-08-10 12:46:08 +0800177 return _eglGetTSD();
Brian Paul40fd1012009-07-17 13:36:06 -0600178}
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{
Chia-I Wu56d21192009-08-10 12:46:08 +0800191 _EGLThreadInfo *t = _eglCheckedGetTSD();
Brian Paul40fd1012009-07-17 13:36:06 -0600192 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 */
204void
205_eglDestroyCurrentThread(void)
206{
Chia-I Wu56d21192009-08-10 12:46:08 +0800207 _EGLThreadInfo *t = _eglCheckedGetTSD();
Brian Paul40fd1012009-07-17 13:36:06 -0600208 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 */
221EGLBoolean
222_eglIsCurrentThreadDummy(void)
223{
Chia-I Wu56d21192009-08-10 12:46:08 +0800224 _EGLThreadInfo *t = _eglCheckedGetTSD();
Brian Paul40fd1012009-07-17 13:36:06 -0600225 return (!t || t == &dummy_thread);
226}
227
228
229/**
230 * Return the currently bound context, or NULL.
231 */
232_EGLContext *
233_eglGetCurrentContext(void)
234{
235 _EGLThreadInfo *t = _eglGetCurrentThread();
236 return t->CurrentContexts[t->CurrentAPIIndex];
237}
238
239
240/**
241 * Return the display of the currently bound context, or NULL.
242 */
243_EGLDisplay *
244_eglGetCurrentDisplay(void)
245{
246 _EGLThreadInfo *t = _eglGetCurrentThread();
247 _EGLContext *ctx = t->CurrentContexts[t->CurrentAPIIndex];
248 if (ctx)
249 return ctx->Display;
250 else
251 return NULL;
252}
253
254
255/**
256 * Return the read or write surface of the currently bound context, or NULL.
257 */
258_EGLSurface *
259_eglGetCurrentSurface(EGLint readdraw)
260{
261 _EGLThreadInfo *t = _eglGetCurrentThread();
262 _EGLContext *ctx = t->CurrentContexts[t->CurrentAPIIndex];
263 if (ctx) {
264 switch (readdraw) {
265 case EGL_DRAW:
266 return ctx->DrawSurface;
267 case EGL_READ:
268 return ctx->ReadSurface;
269 default:
270 return NULL;
271 }
272 }
273 return NULL;
274}
275
276
277/**
278 * Record EGL error code.
279 */
280EGLBoolean
281_eglError(EGLint errCode, const char *msg)
282{
283 _EGLThreadInfo *t = _eglGetCurrentThread();
284 const char *s;
285
286 if (t == &dummy_thread)
287 return EGL_FALSE;
288
289 if (t->LastError == EGL_SUCCESS) {
290 t->LastError = errCode;
291
292 switch (errCode) {
293 case EGL_BAD_ACCESS:
294 s = "EGL_BAD_ACCESS";
295 break;
296 case EGL_BAD_ALLOC:
297 s = "EGL_BAD_ALLOC";
298 break;
299 case EGL_BAD_ATTRIBUTE:
300 s = "EGL_BAD_ATTRIBUTE";
301 break;
302 case EGL_BAD_CONFIG:
303 s = "EGL_BAD_CONFIG";
304 break;
305 case EGL_BAD_CONTEXT:
306 s = "EGL_BAD_CONTEXT";
307 break;
308 case EGL_BAD_CURRENT_SURFACE:
309 s = "EGL_BAD_CURRENT_SURFACE";
310 break;
311 case EGL_BAD_DISPLAY:
312 s = "EGL_BAD_DISPLAY";
313 break;
314 case EGL_BAD_MATCH:
315 s = "EGL_BAD_MATCH";
316 break;
317 case EGL_BAD_NATIVE_PIXMAP:
318 s = "EGL_BAD_NATIVE_PIXMAP";
319 break;
320 case EGL_BAD_NATIVE_WINDOW:
321 s = "EGL_BAD_NATIVE_WINDOW";
322 break;
323 case EGL_BAD_PARAMETER:
324 s = "EGL_BAD_PARAMETER";
325 break;
326 case EGL_BAD_SURFACE:
327 s = "EGL_BAD_SURFACE";
328 break;
329 case EGL_BAD_SCREEN_MESA:
330 s = "EGL_BAD_SCREEN_MESA";
331 break;
332 case EGL_BAD_MODE_MESA:
333 s = "EGL_BAD_MODE_MESA";
334 break;
335 default:
336 s = "other";
337 }
338 _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
339 }
340
341 return EGL_FALSE;
342}