2011-07-02 09:57:30 +01:00
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
* distribute, sub license, and/or sell copies of the Software, and to
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
* the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the
|
|
|
|
* next paragraph) shall be included in all copies or substantial portions
|
|
|
|
* of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
|
2009-07-17 20:36:06 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "egllog.h"
|
2009-08-10 05:20:31 +01:00
|
|
|
#include "eglmutex.h"
|
2010-01-29 01:00:30 +00:00
|
|
|
#include "eglcurrent.h"
|
2010-07-31 21:28:32 +01:00
|
|
|
#include "eglglobals.h"
|
2009-07-17 20:36:06 +01:00
|
|
|
|
|
|
|
|
2009-08-10 05:46:08 +01:00
|
|
|
/* This should be kept in sync with _eglInitThreadInfo() */
|
|
|
|
#define _EGL_THREAD_INFO_INITIALIZER \
|
2009-08-17 08:53:54 +01:00
|
|
|
{ EGL_SUCCESS, { NULL }, 0 }
|
2009-08-10 05:46:08 +01:00
|
|
|
|
2009-07-17 20:36:06 +01:00
|
|
|
/* a fallback thread info to guarantee that every thread always has one */
|
2009-08-10 05:46:08 +01:00
|
|
|
static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
|
2009-07-17 20:36:06 +01:00
|
|
|
|
|
|
|
|
2012-09-19 06:09:26 +01:00
|
|
|
#if HAVE_PTHREAD
|
2009-07-17 20:36:06 +01:00
|
|
|
#include <pthread.h>
|
|
|
|
|
2013-10-11 20:50:21 +01:00
|
|
|
static _EGLMutex _egl_TSDMutex = _EGL_MUTEX_INITIALIZER;
|
2009-08-10 05:20:31 +01:00
|
|
|
static EGLBoolean _egl_TSDInitialized;
|
2009-07-17 20:36:06 +01:00
|
|
|
static pthread_key_t _egl_TSD;
|
2009-08-10 05:20:31 +01:00
|
|
|
static void (*_egl_FreeTSD)(_EGLThreadInfo *);
|
2009-07-17 20:36:06 +01:00
|
|
|
|
2010-11-02 17:11:54 +00:00
|
|
|
#ifdef GLX_USE_TLS
|
|
|
|
static __thread const _EGLThreadInfo *_egl_TLS
|
|
|
|
__attribute__ ((tls_model("initial-exec")));
|
|
|
|
#endif
|
|
|
|
|
2009-08-10 05:20:31 +01:00
|
|
|
static INLINE void _eglSetTSD(const _EGLThreadInfo *t)
|
2009-07-17 20:36:06 +01:00
|
|
|
{
|
2009-08-10 05:20:31 +01:00
|
|
|
pthread_setspecific(_egl_TSD, (const void *) t);
|
2010-11-02 17:11:54 +00:00
|
|
|
#ifdef GLX_USE_TLS
|
|
|
|
_egl_TLS = t;
|
|
|
|
#endif
|
2009-07-17 20:36:06 +01:00
|
|
|
}
|
|
|
|
|
2009-08-10 05:20:31 +01:00
|
|
|
static INLINE _EGLThreadInfo *_eglGetTSD(void)
|
2009-07-17 20:36:06 +01:00
|
|
|
{
|
2010-11-02 17:11:54 +00:00
|
|
|
#ifdef GLX_USE_TLS
|
|
|
|
return (_EGLThreadInfo *) _egl_TLS;
|
|
|
|
#else
|
2009-08-10 05:20:31 +01:00
|
|
|
return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD);
|
2010-11-02 17:11:54 +00:00
|
|
|
#endif
|
2009-07-17 20:36:06 +01:00
|
|
|
}
|
|
|
|
|
2009-08-10 05:20:31 +01:00
|
|
|
static INLINE void _eglFiniTSD(void)
|
2009-07-17 20:36:06 +01:00
|
|
|
{
|
2009-08-10 05:20:31 +01:00
|
|
|
_eglLockMutex(&_egl_TSDMutex);
|
|
|
|
if (_egl_TSDInitialized) {
|
|
|
|
_EGLThreadInfo *t = _eglGetTSD();
|
|
|
|
|
|
|
|
_egl_TSDInitialized = EGL_FALSE;
|
|
|
|
if (t && _egl_FreeTSD)
|
|
|
|
_egl_FreeTSD((void *) t);
|
|
|
|
pthread_key_delete(_egl_TSD);
|
|
|
|
}
|
|
|
|
_eglUnlockMutex(&_egl_TSDMutex);
|
2009-07-17 20:36:06 +01:00
|
|
|
}
|
|
|
|
|
2009-08-10 05:20:31 +01:00
|
|
|
static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
|
2009-07-17 20:36:06 +01:00
|
|
|
{
|
2009-08-10 05:20:31 +01:00
|
|
|
if (!_egl_TSDInitialized) {
|
|
|
|
_eglLockMutex(&_egl_TSDMutex);
|
|
|
|
|
|
|
|
/* check again after acquiring lock */
|
|
|
|
if (!_egl_TSDInitialized) {
|
|
|
|
if (pthread_key_create(&_egl_TSD, (void (*)(void *)) dtor) != 0) {
|
|
|
|
_eglUnlockMutex(&_egl_TSDMutex);
|
|
|
|
return EGL_FALSE;
|
|
|
|
}
|
|
|
|
_egl_FreeTSD = dtor;
|
2009-08-10 09:45:12 +01:00
|
|
|
_eglAddAtExitCall(_eglFiniTSD);
|
2009-08-10 05:20:31 +01:00
|
|
|
_egl_TSDInitialized = EGL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
_eglUnlockMutex(&_egl_TSDMutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
2009-07-17 20:36:06 +01:00
|
|
|
}
|
|
|
|
|
2012-09-19 06:09:26 +01:00
|
|
|
#else /* HAVE_PTHREAD */
|
2009-07-17 20:36:06 +01:00
|
|
|
static const _EGLThreadInfo *_egl_TSD;
|
2009-08-10 05:20:31 +01:00
|
|
|
static void (*_egl_FreeTSD)(_EGLThreadInfo *);
|
2009-07-17 20:36:06 +01:00
|
|
|
|
2009-08-10 05:20:31 +01:00
|
|
|
static INLINE void _eglSetTSD(const _EGLThreadInfo *t)
|
|
|
|
{
|
|
|
|
_egl_TSD = t;
|
|
|
|
}
|
2009-07-17 20:36:06 +01:00
|
|
|
|
|
|
|
static INLINE _EGLThreadInfo *_eglGetTSD(void)
|
|
|
|
{
|
|
|
|
return (_EGLThreadInfo *) _egl_TSD;
|
|
|
|
}
|
2009-08-10 05:20:31 +01:00
|
|
|
|
|
|
|
static INLINE void _eglFiniTSD(void)
|
|
|
|
{
|
|
|
|
if (_egl_FreeTSD && _egl_TSD)
|
|
|
|
_egl_FreeTSD((_EGLThreadInfo *) _egl_TSD);
|
|
|
|
}
|
|
|
|
|
|
|
|
static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
|
|
|
|
{
|
|
|
|
if (!_egl_FreeTSD && dtor) {
|
|
|
|
_egl_FreeTSD = dtor;
|
2009-08-10 09:45:12 +01:00
|
|
|
_eglAddAtExitCall(_eglFiniTSD);
|
2009-08-10 05:20:31 +01:00
|
|
|
}
|
|
|
|
return EGL_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-09-19 06:09:26 +01:00
|
|
|
#endif /* !HAVE_PTHREAD */
|
2009-07-17 20:36:06 +01:00
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2012-09-04 03:44:00 +01:00
|
|
|
_EGLThreadInfo *t = calloc(1, sizeof(_EGLThreadInfo));
|
2009-07-17 20:36:06 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2009-08-10 05:46:08 +01:00
|
|
|
* Make sure TSD is initialized and return current value.
|
2009-07-17 20:36:06 +01:00
|
|
|
*/
|
2009-08-10 05:46:08 +01:00
|
|
|
static INLINE _EGLThreadInfo *
|
|
|
|
_eglCheckedGetTSD(void)
|
2009-07-17 20:36:06 +01:00
|
|
|
{
|
2009-08-10 05:46:08 +01:00
|
|
|
if (_eglInitTSD(&_eglDestroyThreadInfo) != EGL_TRUE) {
|
|
|
|
_eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-07-17 20:36:06 +01:00
|
|
|
|
2009-08-10 05:46:08 +01:00
|
|
|
return _eglGetTSD();
|
2009-07-17 20:36:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
{
|
2009-08-10 05:46:08 +01:00
|
|
|
_EGLThreadInfo *t = _eglCheckedGetTSD();
|
2009-07-17 20:36:06 +01:00
|
|
|
if (!t) {
|
|
|
|
t = _eglCreateThreadInfo();
|
|
|
|
_eglSetTSD(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroy the calling thread's thread info.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
_eglDestroyCurrentThread(void)
|
|
|
|
{
|
2009-08-10 05:46:08 +01:00
|
|
|
_EGLThreadInfo *t = _eglCheckedGetTSD();
|
2009-07-17 20:36:06 +01:00
|
|
|
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)
|
|
|
|
{
|
2009-08-10 05:46:08 +01:00
|
|
|
_EGLThreadInfo *t = _eglCheckedGetTSD();
|
2009-07-17 20:36:06 +01:00
|
|
|
return (!t || t == &dummy_thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2010-01-26 08:52:14 +00:00
|
|
|
* Return the currently bound context of the given API, or NULL.
|
|
|
|
*/
|
|
|
|
PUBLIC _EGLContext *
|
|
|
|
_eglGetAPIContext(EGLenum api)
|
|
|
|
{
|
|
|
|
_EGLThreadInfo *t = _eglGetCurrentThread();
|
|
|
|
return t->CurrentContexts[_eglConvertApiToIndex(api)];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the currently bound context of the current API, or NULL.
|
2009-07-17 20:36:06 +01:00
|
|
|
*/
|
|
|
|
_EGLContext *
|
|
|
|
_eglGetCurrentContext(void)
|
|
|
|
{
|
|
|
|
_EGLThreadInfo *t = _eglGetCurrentThread();
|
|
|
|
return t->CurrentContexts[t->CurrentAPIIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2010-02-17 08:42:30 +00:00
|
|
|
* Record EGL error code and return EGL_FALSE.
|
2009-07-17 20:36:06 +01:00
|
|
|
*/
|
|
|
|
EGLBoolean
|
|
|
|
_eglError(EGLint errCode, const char *msg)
|
|
|
|
{
|
|
|
|
_EGLThreadInfo *t = _eglGetCurrentThread();
|
|
|
|
|
|
|
|
if (t == &dummy_thread)
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
2010-02-17 08:42:30 +00:00
|
|
|
t->LastError = errCode;
|
|
|
|
|
|
|
|
if (errCode != EGL_SUCCESS) {
|
|
|
|
const char *s;
|
2009-07-17 20:36:06 +01:00
|
|
|
|
|
|
|
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;
|
2010-12-31 16:14:19 +00:00
|
|
|
case EGL_NOT_INITIALIZED:
|
|
|
|
s = "EGL_NOT_INITIALIZED";
|
|
|
|
break;
|
2010-07-30 17:00:49 +01:00
|
|
|
#ifdef EGL_MESA_screen_surface
|
2009-07-17 20:36:06 +01:00
|
|
|
case EGL_BAD_SCREEN_MESA:
|
|
|
|
s = "EGL_BAD_SCREEN_MESA";
|
|
|
|
break;
|
|
|
|
case EGL_BAD_MODE_MESA:
|
|
|
|
s = "EGL_BAD_MODE_MESA";
|
|
|
|
break;
|
2010-07-30 17:00:49 +01:00
|
|
|
#endif
|
2009-07-17 20:36:06 +01:00
|
|
|
default:
|
2010-12-31 16:14:19 +00:00
|
|
|
s = "other EGL error";
|
2009-07-17 20:36:06 +01:00
|
|
|
}
|
|
|
|
_eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
}
|