Merge change 21646 into eclair
* changes: fix bug [2021677] egl driver unloaded after eglTerminate() is called
This commit is contained in:
@@ -50,7 +50,7 @@ namespace android {
|
|||||||
#define VERSION_MAJOR 1
|
#define VERSION_MAJOR 1
|
||||||
#define VERSION_MINOR 4
|
#define VERSION_MINOR 4
|
||||||
static char const * const gVendorString = "Android";
|
static char const * const gVendorString = "Android";
|
||||||
static char const * const gVersionString = "1.31 Android META-EGL";
|
static char const * const gVersionString = "1.4 Android META-EGL";
|
||||||
static char const * const gClientApiString = "OpenGL ES";
|
static char const * const gClientApiString = "OpenGL ES";
|
||||||
static char const * const gExtensionString =
|
static char const * const gExtensionString =
|
||||||
"EGL_KHR_image "
|
"EGL_KHR_image "
|
||||||
@@ -326,32 +326,6 @@ static void(*findProcAddress(const char* name,
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
|
||||||
* To "loose" the GPU, use something like
|
|
||||||
* gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int gl_context_lost() {
|
|
||||||
setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int egl_context_lost() {
|
|
||||||
setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
|
|
||||||
usleep(100000); // don't use all the CPU
|
|
||||||
setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
static GLint egl_context_lost_get_error() {
|
|
||||||
return EGL_CONTEXT_LOST;
|
|
||||||
}
|
|
||||||
static int ext_context_lost() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_no_context() {
|
static void gl_no_context() {
|
||||||
tls_t* tls = getTLS();
|
tls_t* tls = getTLS();
|
||||||
if (tls->logCallWithNoContext == EGL_TRUE) {
|
if (tls->logCallWithNoContext == EGL_TRUE) {
|
||||||
@@ -471,87 +445,82 @@ EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
|
|||||||
return i->images[c->impl];
|
return i->images[c->impl];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
EGLDisplay egl_init_displays(NativeDisplayType display)
|
// this mutex protects:
|
||||||
|
// d->dpys[]
|
||||||
|
// egl_init_drivers_locked()
|
||||||
|
//
|
||||||
|
static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
EGLBoolean egl_init_drivers_locked()
|
||||||
{
|
{
|
||||||
if (sEarlyInitState) {
|
if (sEarlyInitState) {
|
||||||
return EGL_NO_DISPLAY;
|
// initialized by static ctor. should be set here.
|
||||||
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t index = uint32_t(display);
|
|
||||||
if (index >= NUM_DISPLAYS) {
|
|
||||||
return EGL_NO_DISPLAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
|
|
||||||
egl_display_t* d = &gDisplay[index];
|
|
||||||
|
|
||||||
// get our driver loader
|
// get our driver loader
|
||||||
Loader& loader(Loader::getInstance());
|
Loader& loader(Loader::getInstance());
|
||||||
|
|
||||||
// dynamically load all our EGL implementations for that display
|
// dynamically load all our EGL implementations for all displays
|
||||||
// and call into the real eglGetGisplay()
|
// and retrieve the corresponding EGLDisplay
|
||||||
egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
|
// if that fails, don't use this driver.
|
||||||
|
// TODO: currently we only deal with EGL_DEFAULT_DISPLAY
|
||||||
|
egl_connection_t* cnx;
|
||||||
|
egl_display_t* d = &gDisplay[0];
|
||||||
|
|
||||||
|
cnx = &gEGLImpl[IMPL_SOFTWARE];
|
||||||
if (cnx->dso == 0) {
|
if (cnx->dso == 0) {
|
||||||
cnx->hooks = &gHooks[IMPL_SOFTWARE];
|
cnx->hooks = &gHooks[IMPL_SOFTWARE];
|
||||||
cnx->dso = loader.open(display, 0, cnx->hooks);
|
cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx->hooks);
|
||||||
}
|
if (cnx->dso) {
|
||||||
if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
|
EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
|
LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
|
||||||
LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
|
d->dpys[IMPL_SOFTWARE] = dpy;
|
||||||
"No EGLDisplay for software EGL!");
|
if (dpy == EGL_NO_DISPLAY) {
|
||||||
|
loader.close(cnx->dso);
|
||||||
|
cnx->dso = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cnx = &gEGLImpl[IMPL_HARDWARE];
|
cnx = &gEGLImpl[IMPL_HARDWARE];
|
||||||
if (cnx->dso == 0 && cnx->unavailable == 0) {
|
if (cnx->dso == 0) {
|
||||||
char value[PROPERTY_VALUE_MAX];
|
char value[PROPERTY_VALUE_MAX];
|
||||||
property_get("debug.egl.hw", value, "1");
|
property_get("debug.egl.hw", value, "1");
|
||||||
if (atoi(value) != 0) {
|
if (atoi(value) != 0) {
|
||||||
cnx->hooks = &gHooks[IMPL_HARDWARE];
|
cnx->hooks = &gHooks[IMPL_HARDWARE];
|
||||||
cnx->dso = loader.open(display, 1, cnx->hooks);
|
cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx->hooks);
|
||||||
|
if (cnx->dso) {
|
||||||
|
EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
|
LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
|
||||||
|
d->dpys[IMPL_HARDWARE] = dpy;
|
||||||
|
if (dpy == EGL_NO_DISPLAY) {
|
||||||
|
loader.close(cnx->dso);
|
||||||
|
cnx->dso = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGD("3D hardware acceleration is disabled");
|
LOGD("3D hardware acceleration is disabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
|
|
||||||
android_memset32(
|
if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
|
||||||
(uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
|
return EGL_FALSE;
|
||||||
(uint32_t)((void*)gl_context_lost),
|
|
||||||
sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
|
|
||||||
android_memset32(
|
|
||||||
(uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
|
|
||||||
(uint32_t)((void*)egl_context_lost),
|
|
||||||
sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
|
|
||||||
android_memset32(
|
|
||||||
(uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
|
|
||||||
(uint32_t)((void*)ext_context_lost),
|
|
||||||
sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
|
|
||||||
|
|
||||||
gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
|
|
||||||
egl_context_lost_swap_buffers;
|
|
||||||
|
|
||||||
gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
|
|
||||||
egl_context_lost_get_error;
|
|
||||||
|
|
||||||
gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
|
|
||||||
gHooks[IMPL_HARDWARE].egl.eglTerminate;
|
|
||||||
|
|
||||||
d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
|
|
||||||
if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
|
|
||||||
LOGE("h/w accelerated eglGetDisplay() failed (%s)",
|
|
||||||
egl_strerror(cnx->hooks->egl.eglGetError()));
|
|
||||||
|
|
||||||
loader.close(cnx->dso);
|
|
||||||
cnx->dso = 0;
|
|
||||||
// in case of failure, we want to make sure we don't try again
|
|
||||||
// as it's expensive.
|
|
||||||
cnx->unavailable = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dpy;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EGLBoolean egl_init_drivers()
|
||||||
|
{
|
||||||
|
EGLBoolean res;
|
||||||
|
pthread_mutex_lock(&gInitDriverMutex);
|
||||||
|
res = egl_init_drivers_locked();
|
||||||
|
pthread_mutex_unlock(&gInitDriverMutex);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
@@ -561,7 +530,17 @@ using namespace android;
|
|||||||
|
|
||||||
EGLDisplay eglGetDisplay(NativeDisplayType display)
|
EGLDisplay eglGetDisplay(NativeDisplayType display)
|
||||||
{
|
{
|
||||||
return egl_init_displays(display);
|
uint32_t index = uint32_t(display);
|
||||||
|
if (index >= NUM_DISPLAYS) {
|
||||||
|
return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (egl_init_drivers() == EGL_FALSE) {
|
||||||
|
return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
|
||||||
|
return dpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -648,31 +627,25 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
|
|||||||
|
|
||||||
EGLBoolean eglTerminate(EGLDisplay dpy)
|
EGLBoolean eglTerminate(EGLDisplay dpy)
|
||||||
{
|
{
|
||||||
|
// NOTE: don't unload the drivers b/c some APIs can be called
|
||||||
|
// after eglTerminate() has been called. eglTerminate() only
|
||||||
|
// terminates an EGLDisplay, not a EGL itself.
|
||||||
|
|
||||||
egl_display_t* const dp = get_display(dpy);
|
egl_display_t* const dp = get_display(dpy);
|
||||||
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
|
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
|
||||||
if (android_atomic_dec(&dp->refs) != 1)
|
if (android_atomic_dec(&dp->refs) != 1)
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
|
|
||||||
Loader& loader(Loader::getInstance());
|
|
||||||
|
|
||||||
EGLBoolean res = EGL_FALSE;
|
EGLBoolean res = EGL_FALSE;
|
||||||
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
|
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
|
||||||
egl_connection_t* const cnx = &gEGLImpl[i];
|
egl_connection_t* const cnx = &gEGLImpl[i];
|
||||||
if (cnx->dso) {
|
if (cnx->dso) {
|
||||||
cnx->hooks->egl.eglTerminate(dp->dpys[i]);
|
cnx->hooks->egl.eglTerminate(dp->dpys[i]);
|
||||||
|
// REVISIT: it's unclear what to do if eglTerminate() fails
|
||||||
/* REVISIT: it's unclear what to do if eglTerminate() fails,
|
|
||||||
* on one end we shouldn't care, on the other end if it fails
|
|
||||||
* it might not be safe to call dlclose() (there could be some
|
|
||||||
* threads around). */
|
|
||||||
|
|
||||||
free(dp->configs[i]);
|
free(dp->configs[i]);
|
||||||
free((void*)dp->queryString[i].extensions);
|
free((void*)dp->queryString[i].extensions);
|
||||||
dp->numConfigs[i] = 0;
|
dp->numConfigs[i] = 0;
|
||||||
dp->dpys[i] = EGL_NO_DISPLAY;
|
dp->dpys[i] = EGL_NO_DISPLAY;
|
||||||
|
|
||||||
loader.close(cnx->dso);
|
|
||||||
cnx->dso = 0;
|
|
||||||
res = EGL_TRUE;
|
res = EGL_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1022,12 +995,18 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
|
|||||||
|
|
||||||
EGLContext eglGetCurrentContext(void)
|
EGLContext eglGetCurrentContext(void)
|
||||||
{
|
{
|
||||||
|
// could be called before eglInitialize(), but we wouldn't have a context
|
||||||
|
// then, and this function would correctly return EGL_NO_CONTEXT.
|
||||||
|
|
||||||
EGLContext ctx = getContext();
|
EGLContext ctx = getContext();
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLSurface eglGetCurrentSurface(EGLint readdraw)
|
EGLSurface eglGetCurrentSurface(EGLint readdraw)
|
||||||
{
|
{
|
||||||
|
// could be called before eglInitialize(), but we wouldn't have a context
|
||||||
|
// then, and this function would correctly return EGL_NO_SURFACE.
|
||||||
|
|
||||||
EGLContext ctx = getContext();
|
EGLContext ctx = getContext();
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
egl_context_t const * const c = get_context(ctx);
|
egl_context_t const * const c = get_context(ctx);
|
||||||
@@ -1043,6 +1022,9 @@ EGLSurface eglGetCurrentSurface(EGLint readdraw)
|
|||||||
|
|
||||||
EGLDisplay eglGetCurrentDisplay(void)
|
EGLDisplay eglGetCurrentDisplay(void)
|
||||||
{
|
{
|
||||||
|
// could be called before eglInitialize(), but we wouldn't have a context
|
||||||
|
// then, and this function would correctly return EGL_NO_DISPLAY.
|
||||||
|
|
||||||
EGLContext ctx = getContext();
|
EGLContext ctx = getContext();
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
egl_context_t const * const c = get_context(ctx);
|
egl_context_t const * const c = get_context(ctx);
|
||||||
@@ -1054,6 +1036,9 @@ EGLDisplay eglGetCurrentDisplay(void)
|
|||||||
|
|
||||||
EGLBoolean eglWaitGL(void)
|
EGLBoolean eglWaitGL(void)
|
||||||
{
|
{
|
||||||
|
// could be called before eglInitialize(), but we wouldn't have a context
|
||||||
|
// then, and this function would return GL_TRUE, which isn't wrong.
|
||||||
|
|
||||||
EGLBoolean res = EGL_TRUE;
|
EGLBoolean res = EGL_TRUE;
|
||||||
EGLContext ctx = getContext();
|
EGLContext ctx = getContext();
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
@@ -1071,6 +1056,9 @@ EGLBoolean eglWaitGL(void)
|
|||||||
|
|
||||||
EGLBoolean eglWaitNative(EGLint engine)
|
EGLBoolean eglWaitNative(EGLint engine)
|
||||||
{
|
{
|
||||||
|
// could be called before eglInitialize(), but we wouldn't have a context
|
||||||
|
// then, and this function would return GL_TRUE, which isn't wrong.
|
||||||
|
|
||||||
EGLBoolean res = EGL_TRUE;
|
EGLBoolean res = EGL_TRUE;
|
||||||
EGLContext ctx = getContext();
|
EGLContext ctx = getContext();
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
@@ -1107,9 +1095,11 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
|
|||||||
// eglGetProcAddress() could be the very first function called
|
// eglGetProcAddress() could be the very first function called
|
||||||
// in which case we must make sure we've initialized ourselves, this
|
// in which case we must make sure we've initialized ourselves, this
|
||||||
// happens the first time egl_get_display() is called.
|
// happens the first time egl_get_display() is called.
|
||||||
|
|
||||||
if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
|
if (egl_init_drivers() == EGL_FALSE) {
|
||||||
return NULL;
|
setError(EGL_BAD_PARAMETER, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
__eglMustCastToProperFunctionPointerType addr;
|
__eglMustCastToProperFunctionPointerType addr;
|
||||||
addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
|
addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
|
||||||
@@ -1275,6 +1265,8 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
|
|||||||
|
|
||||||
EGLBoolean eglWaitClient(void)
|
EGLBoolean eglWaitClient(void)
|
||||||
{
|
{
|
||||||
|
// could be called before eglInitialize(), but we wouldn't have a context
|
||||||
|
// then, and this function would return GL_TRUE, which isn't wrong.
|
||||||
EGLBoolean res = EGL_TRUE;
|
EGLBoolean res = EGL_TRUE;
|
||||||
EGLContext ctx = getContext();
|
EGLContext ctx = getContext();
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
@@ -1296,6 +1288,10 @@ EGLBoolean eglWaitClient(void)
|
|||||||
|
|
||||||
EGLBoolean eglBindAPI(EGLenum api)
|
EGLBoolean eglBindAPI(EGLenum api)
|
||||||
{
|
{
|
||||||
|
if (egl_init_drivers() == EGL_FALSE) {
|
||||||
|
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
// bind this API on all EGLs
|
// bind this API on all EGLs
|
||||||
EGLBoolean res = EGL_TRUE;
|
EGLBoolean res = EGL_TRUE;
|
||||||
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
|
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
|
||||||
@@ -1313,6 +1309,10 @@ EGLBoolean eglBindAPI(EGLenum api)
|
|||||||
|
|
||||||
EGLenum eglQueryAPI(void)
|
EGLenum eglQueryAPI(void)
|
||||||
{
|
{
|
||||||
|
if (egl_init_drivers() == EGL_FALSE) {
|
||||||
|
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
|
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
|
||||||
egl_connection_t* const cnx = &gEGLImpl[i];
|
egl_connection_t* const cnx = &gEGLImpl[i];
|
||||||
if (cnx->dso) {
|
if (cnx->dso) {
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ struct egl_connection_t
|
|||||||
gl_hooks_t * hooks;
|
gl_hooks_t * hooks;
|
||||||
EGLint major;
|
EGLint major;
|
||||||
EGLint minor;
|
EGLint minor;
|
||||||
int unavailable;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
|
EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
|
||||||
|
|||||||
@@ -60,12 +60,8 @@ const unsigned int NUM_DISPLAYS = 1;
|
|||||||
enum {
|
enum {
|
||||||
IMPL_HARDWARE = 0,
|
IMPL_HARDWARE = 0,
|
||||||
IMPL_SOFTWARE,
|
IMPL_SOFTWARE,
|
||||||
|
|
||||||
IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
|
IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
|
||||||
|
IMPL_NO_CONTEXT = IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
|
||||||
IMPL_CONTEXT_LOST = IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
|
|
||||||
IMPL_NO_CONTEXT,
|
|
||||||
|
|
||||||
IMPL_NUM_IMPLEMENTATIONS
|
IMPL_NUM_IMPLEMENTATIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user