egl_dri2: Fix initialization with EGL_DEFAULT_DISPLAY
[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.
252 */
253 EGLBoolean
254 _eglError(EGLint errCode, const char *msg)
255 {
256 _EGLThreadInfo *t = _eglGetCurrentThread();
257 const char *s;
258
259 if (t == &dummy_thread)
260 return EGL_FALSE;
261
262 if (t->LastError == EGL_SUCCESS) {
263 t->LastError = errCode;
264
265 switch (errCode) {
266 case EGL_BAD_ACCESS:
267 s = "EGL_BAD_ACCESS";
268 break;
269 case EGL_BAD_ALLOC:
270 s = "EGL_BAD_ALLOC";
271 break;
272 case EGL_BAD_ATTRIBUTE:
273 s = "EGL_BAD_ATTRIBUTE";
274 break;
275 case EGL_BAD_CONFIG:
276 s = "EGL_BAD_CONFIG";
277 break;
278 case EGL_BAD_CONTEXT:
279 s = "EGL_BAD_CONTEXT";
280 break;
281 case EGL_BAD_CURRENT_SURFACE:
282 s = "EGL_BAD_CURRENT_SURFACE";
283 break;
284 case EGL_BAD_DISPLAY:
285 s = "EGL_BAD_DISPLAY";
286 break;
287 case EGL_BAD_MATCH:
288 s = "EGL_BAD_MATCH";
289 break;
290 case EGL_BAD_NATIVE_PIXMAP:
291 s = "EGL_BAD_NATIVE_PIXMAP";
292 break;
293 case EGL_BAD_NATIVE_WINDOW:
294 s = "EGL_BAD_NATIVE_WINDOW";
295 break;
296 case EGL_BAD_PARAMETER:
297 s = "EGL_BAD_PARAMETER";
298 break;
299 case EGL_BAD_SURFACE:
300 s = "EGL_BAD_SURFACE";
301 break;
302 case EGL_BAD_SCREEN_MESA:
303 s = "EGL_BAD_SCREEN_MESA";
304 break;
305 case EGL_BAD_MODE_MESA:
306 s = "EGL_BAD_MODE_MESA";
307 break;
308 default:
309 s = "other";
310 }
311 _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
312 }
313
314 return EGL_FALSE;
315 }