summaryrefslogtreecommitdiffstats
path: root/src/egl/main/eglcurrent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/main/eglcurrent.c')
-rw-r--r--src/egl/main/eglcurrent.c283
1 files changed, 283 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;
+}