eglcurrent.c revision 4a49301e
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 }, 0 }
13
14/* a fallback thread info to guarantee that every thread always has one */
15static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
16
17
18#ifdef GLX_USE_TLS
19static __thread const _EGLThreadInfo *_egl_TSD
20   __attribute__ ((tls_model("initial-exec")));
21
22static INLINE void _eglSetTSD(const _EGLThreadInfo *t)
23{
24   _egl_TSD = t;
25}
26
27static INLINE _EGLThreadInfo *_eglGetTSD(void)
28{
29   return (_EGLThreadInfo *) _egl_TSD;
30}
31
32static INLINE void _eglFiniTSD(void)
33{
34}
35
36static 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
47static _EGL_DECLARE_MUTEX(_egl_TSDMutex);
48static EGLBoolean _egl_TSDInitialized;
49static pthread_key_t _egl_TSD;
50static void (*_egl_FreeTSD)(_EGLThreadInfo *);
51
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
62static 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;
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 */
99static const _EGLThreadInfo *_egl_TSD;
100static void (*_egl_FreeTSD)(_EGLThreadInfo *);
101
102static INLINE void _eglSetTSD(const _EGLThreadInfo *t)
103{
104   _egl_TSD = t;
105}
106
107static INLINE _EGLThreadInfo *_eglGetTSD(void)
108{
109   return (_EGLThreadInfo *) _egl_TSD;
110}
111
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;
122      _eglAddAtExitCall(_eglFiniTSD);
123   }
124   return EGL_TRUE;
125}
126
127#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/**
167 * Make sure TSD is initialized and return current value.
168 */
169static 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 */
204void
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 */
221EGLBoolean
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 */
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}
343