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