diff options
Diffstat (limited to 'src/egl')
-rw-r--r-- | src/egl/main/eglcurrent.c | 283 | ||||
-rw-r--r-- | src/egl/main/eglcurrent.h | 92 |
2 files changed, 375 insertions, 0 deletions
diff --git a/src/egl/main/eglcurrent.c b/src/egl/main/eglcurrent.c new file mode 100644 index 00000000000..96152db19fb --- /dev/null +++ b/src/egl/main/eglcurrent.c @@ -0,0 +1,283 @@ +#include <stdlib.h> +#include <string.h> +#include "eglcurrent.h" +#include "eglcontext.h" +#include "egllog.h" + + +/* a fallback thread info to guarantee that every thread always has one */ +static _EGLThreadInfo dummy_thread; + + +#ifdef GLX_USE_TLS +static __thread const _EGLThreadInfo *_egl_TSD; + __attribute__ ((tls_model("initial-exec"))); + +static INLINE EGLBoolean _eglInitTSD(void) { return EGL_TRUE; } +static INLINE void _eglFiniTSD(void) { } +static INLINE void _eglSetTSD(const _EGLThreadInfo *t) { _egl_TSD = t; } + +static INLINE _EGLThreadInfo *_eglGetTSD(void) +{ + return (_EGLThreadInfo *) _egl_TSD; +} + +#elif PTHREADS +#include <pthread.h> + +static pthread_key_t _egl_TSD; + +static INLINE EGLBoolean _eglInitTSD(void) +{ + return (pthread_key_create(&_egl_TSD, NULL) == 0); +} + +static INLINE void _eglFiniTSD(void) +{ + pthread_key_delete(_egl_TSD); +} + +static INLINE void _eglSetTSD(const _EGLThreadInfo *t) +{ + pthread_setspecific(_egl_TSD, (const void *) t); +} + +static INLINE _EGLThreadInfo *_eglGetTSD(void) +{ + return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD); +} + +#else /* PTHREADS */ +static const _EGLThreadInfo *_egl_TSD; + +static INLINE EGLBoolean _eglInitTSD(void) { return EGL_TRUE; } +static INLINE void _eglFiniTSD(void) { } +static INLINE void _eglSetTSD(const _EGLThreadInfo *t) { _egl_TSD = t; } + +static INLINE _EGLThreadInfo *_eglGetTSD(void) +{ + return (_EGLThreadInfo *) _egl_TSD; +} +#endif /* !PTHREADS */ + + +static void +_eglInitThreadInfo(_EGLThreadInfo *t) +{ + memset(t, 0, sizeof(*t)); + t->LastError = EGL_SUCCESS; + /* default, per EGL spec */ + t->CurrentAPIIndex = _eglConvertApiToIndex(EGL_OPENGL_ES_API); +} + + +/** + * Allocate and init a new _EGLThreadInfo object. + */ +static _EGLThreadInfo * +_eglCreateThreadInfo(void) +{ + _EGLThreadInfo *t = (_EGLThreadInfo *) calloc(1, sizeof(_EGLThreadInfo)); + if (t) + _eglInitThreadInfo(t); + else + t = &dummy_thread; + return t; +} + + +/** + * Delete/free a _EGLThreadInfo object. + */ +static void +_eglDestroyThreadInfo(_EGLThreadInfo *t) +{ + if (t != &dummy_thread) + free(t); +} + + +/** + * Initialize "current thread" management. + */ +EGLBoolean +_eglInitCurrent(void) +{ + _eglInitThreadInfo(&dummy_thread); + return _eglInitTSD(); +} + + +/** + * Finish "current thread" management. + */ +void +_eglFiniCurrent(void) +{ + /* TODO trace and release all threads... */ + _eglFiniTSD(); +} + + +/** + * Return the calling thread's thread info. + * If the calling thread nevers calls this function before, or if its thread + * info was destroyed, a new one is created. This function never returns NULL. + * In the case allocation fails, a dummy one is returned. See also + * _eglIsCurrentThreadDummy. + */ +_EGLThreadInfo * +_eglGetCurrentThread(void) +{ + _EGLThreadInfo *t = _eglGetTSD(); + if (!t) { + t = _eglCreateThreadInfo(); + _eglSetTSD(t); + } + + return t; +} + + +/** + * Destroy the calling thread's thread info. + */ +void +_eglDestroyCurrentThread(void) +{ + _EGLThreadInfo *t = _eglGetTSD(); + if (t) { + _eglDestroyThreadInfo(t); + _eglSetTSD(NULL); + } +} + + +/** + * Return true if the calling thread's thread info is dummy. + * A dummy thread info is shared by all threads and should not be modified. + * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness + * before updating the thread info. + */ +EGLBoolean +_eglIsCurrentThreadDummy(void) +{ + _EGLThreadInfo *t = _eglGetTSD(); + return (!t || t == &dummy_thread); +} + + +/** + * Return the currently bound context, or NULL. + */ +_EGLContext * +_eglGetCurrentContext(void) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + return t->CurrentContexts[t->CurrentAPIIndex]; +} + + +/** + * Return the display of the currently bound context, or NULL. + */ +_EGLDisplay * +_eglGetCurrentDisplay(void) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + _EGLContext *ctx = t->CurrentContexts[t->CurrentAPIIndex]; + if (ctx) + return ctx->Display; + else + return NULL; +} + + +/** + * Return the read or write surface of the currently bound context, or NULL. + */ +_EGLSurface * +_eglGetCurrentSurface(EGLint readdraw) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + _EGLContext *ctx = t->CurrentContexts[t->CurrentAPIIndex]; + if (ctx) { + switch (readdraw) { + case EGL_DRAW: + return ctx->DrawSurface; + case EGL_READ: + return ctx->ReadSurface; + default: + return NULL; + } + } + return NULL; +} + + +/** + * Record EGL error code. + */ +EGLBoolean +_eglError(EGLint errCode, const char *msg) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + const char *s; + + if (t == &dummy_thread) + return EGL_FALSE; + + if (t->LastError == EGL_SUCCESS) { + t->LastError = errCode; + + switch (errCode) { + case EGL_BAD_ACCESS: + s = "EGL_BAD_ACCESS"; + break; + case EGL_BAD_ALLOC: + s = "EGL_BAD_ALLOC"; + break; + case EGL_BAD_ATTRIBUTE: + s = "EGL_BAD_ATTRIBUTE"; + break; + case EGL_BAD_CONFIG: + s = "EGL_BAD_CONFIG"; + break; + case EGL_BAD_CONTEXT: + s = "EGL_BAD_CONTEXT"; + break; + case EGL_BAD_CURRENT_SURFACE: + s = "EGL_BAD_CURRENT_SURFACE"; + break; + case EGL_BAD_DISPLAY: + s = "EGL_BAD_DISPLAY"; + break; + case EGL_BAD_MATCH: + s = "EGL_BAD_MATCH"; + break; + case EGL_BAD_NATIVE_PIXMAP: + s = "EGL_BAD_NATIVE_PIXMAP"; + break; + case EGL_BAD_NATIVE_WINDOW: + s = "EGL_BAD_NATIVE_WINDOW"; + break; + case EGL_BAD_PARAMETER: + s = "EGL_BAD_PARAMETER"; + break; + case EGL_BAD_SURFACE: + s = "EGL_BAD_SURFACE"; + break; + case EGL_BAD_SCREEN_MESA: + s = "EGL_BAD_SCREEN_MESA"; + break; + case EGL_BAD_MODE_MESA: + s = "EGL_BAD_MODE_MESA"; + break; + default: + s = "other"; + } + _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg); + } + + return EGL_FALSE; +} diff --git a/src/egl/main/eglcurrent.h b/src/egl/main/eglcurrent.h new file mode 100644 index 00000000000..f9fdf7bd0f0 --- /dev/null +++ b/src/egl/main/eglcurrent.h @@ -0,0 +1,92 @@ +#ifndef EGLCURRENT_INCLUDED +#define EGLCURRENT_INCLUDED + +#include "egltypedefs.h" + + +#define _EGL_API_NUM_INDICES \ + (EGL_OPENGL_API - EGL_OPENGL_ES_API + 2) /* idx 0 is for EGL_NONE */ + + +/** + * Per-thread info + */ +struct _egl_thread_info +{ + EGLint LastError; + _EGLContext *CurrentContexts[_EGL_API_NUM_INDICES]; + /* use index for fast access to current context */ + EGLint CurrentAPIIndex; +}; + + +extern EGLBoolean +_eglInitCurrent(void); + + +extern void +_eglFiniCurrent(void); + + +/** + * Return true if a client API enum can be converted to an index. + */ +static INLINE EGLBoolean +_eglIsApiValid(EGLenum api) +{ + return ((api >= EGL_OPENGL_ES_API && api <= EGL_OPENGL_API) || + api == EGL_NONE); +} + + +/** + * Convert a client API enum to an index, for use by thread info. + * The client API enum is assumed to be valid. + */ +static INLINE EGLint +_eglConvertApiToIndex(EGLenum api) +{ + return (api != EGL_NONE) ? api - EGL_OPENGL_ES_API + 1 : 0; +} + + +/** + * Convert an index, used by thread info, to a client API enum. + * The index is assumed to be valid. + */ +static INLINE EGLenum +_eglConvertApiFromIndex(EGLint idx) +{ + return (idx) ? EGL_OPENGL_ES_API + idx - 1 : EGL_NONE; +} + + +extern _EGLThreadInfo * +_eglGetCurrentThread(void); + + +extern void +_eglDestroyCurrentThread(void); + + +extern EGLBoolean +_eglIsCurrentThreadDummy(void); + + +extern _EGLContext * +_eglGetCurrentContext(void); + + +extern _EGLDisplay * +_eglGetCurrentDisplay(void); + + +extern _EGLSurface * +_eglGetCurrentSurface(EGLint readdraw); + + +extern EGLBoolean +_eglError(EGLint errCode, const char *msg); + + +#endif /* EGLCURRENT_INCLUDED */ |