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