Merge branch 'vbo_clean'
[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 }, 1 }
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, 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 */
280 EGLBoolean
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 }