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