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