egl: Make eglMakeCurrent more robust.

Now that a current surface points back to its binding context, and a
current context points back to its binding thread, make sure there is no
dangling pointers.  This commit reworks eglMakeCurrent, adds more checks
to avoid stealing context or surfaces from another thread, and correctly
destroys unlinked context and surfaces.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
This commit is contained in:
Chia-I Wu 2009-08-03 11:35:14 -06:00 committed by Brian Paul
parent 07ee01365a
commit 8cdc6c66f9
1 changed files with 49 additions and 55 deletions

View File

@ -146,10 +146,11 @@ _eglQueryContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx,
* Then, the driver will do its device-dependent Make-Current stuff.
*/
EGLBoolean
_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
_eglMakeCurrent(_EGLDriver *drv, EGLDisplay display, EGLSurface d,
EGLSurface r, EGLContext context)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
_EGLDisplay *dpy = _eglLookupDisplay(display);
_EGLContext *ctx = _eglLookupContext(context);
_EGLSurface *draw = _eglLookupSurface(d);
_EGLSurface *read = _eglLookupSurface(r);
@ -160,21 +161,23 @@ _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
if (_eglIsCurrentThreadDummy())
return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
if (dpy == NULL)
return _eglError(EGL_BAD_DISPLAY, "eglMakeCurrent");
/* error checking */
if (ctx) {
/* error checking */
if (ctx->Binding && ctx->Binding != t)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
if (draw == NULL || read == NULL) {
_eglError(EGL_BAD_MATCH, "eglMakeCurrent");
return EGL_FALSE;
}
if (draw->Config != ctx->Config) {
_eglError(EGL_BAD_MATCH, "eglMakeCurrent");
return EGL_FALSE;
}
if (read->Config != ctx->Config) {
_eglError(EGL_BAD_MATCH, "eglMakeCurrent");
return EGL_FALSE;
EGLint err = (d == EGL_NO_SURFACE || r == EGL_NO_SURFACE)
? EGL_BAD_MATCH : EGL_BAD_SURFACE;
return _eglError(err, "eglMakeCurrent");
}
if (draw->Config != ctx->Config || read->Config != ctx->Config)
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
if ((draw->Binding && draw->Binding->Binding != t) ||
(read->Binding && read->Binding->Binding != t))
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
#ifdef EGL_VERSION_1_4
/* OpenGL and OpenGL ES are conflicting */
@ -194,6 +197,10 @@ _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
apiIndex = _eglConvertApiToIndex(ctx->ClientAPI);
}
else {
if (context != EGL_NO_CONTEXT)
return _eglError(EGL_BAD_CONTEXT, "eglMakeCurrent");
if (draw != NULL || read != NULL)
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
apiIndex = t->CurrentAPIIndex;
}
@ -201,60 +208,47 @@ _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
if (oldContext) {
oldDrawSurface = oldContext->DrawSurface;
oldReadSurface = oldContext->ReadSurface;
}
assert(oldDrawSurface);
assert(oldReadSurface);
/*
* check if the old context or surfaces need to be deleted
*/
if (oldDrawSurface != NULL) {
oldDrawSurface->Binding = NULL;
if (!_eglIsSurfaceLinked(oldDrawSurface)) {
/* make sure we don't try to rebind a deleted surface */
if (draw == oldDrawSurface || draw == oldReadSurface) {
draw = NULL;
}
/* really delete surface now */
drv->API.DestroySurface(drv, dpy, oldDrawSurface->Handle);
}
}
if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) {
oldReadSurface->Binding = NULL;
if (!_eglIsSurfaceLinked(oldReadSurface)) {
/* make sure we don't try to rebind a deleted surface */
if (read == oldDrawSurface || read == oldReadSurface) {
read = NULL;
}
/* really delete surface now */
drv->API.DestroySurface(drv, dpy, oldReadSurface->Handle);
}
}
if (oldContext != NULL) {
/* break old bindings */
t->CurrentContexts[apiIndex] = NULL;
oldContext->Binding = NULL;
oldContext->DrawSurface = NULL;
oldContext->ReadSurface = NULL;
oldDrawSurface->Binding = NULL;
oldReadSurface->Binding = NULL;
/*
* check if the old context or surfaces need to be deleted
* FIXME They are linked so that they can be unlinked. This is ugly.
*/
if (!_eglIsSurfaceLinked(oldDrawSurface)) {
assert(draw != oldDrawSurface && read != oldDrawSurface);
drv->API.DestroySurface(drv, display,
_eglLinkSurface(oldDrawSurface, dpy));
}
if (oldReadSurface != oldDrawSurface &&
!_eglIsSurfaceLinked(oldReadSurface)) {
assert(draw != oldReadSurface && read != oldReadSurface);
drv->API.DestroySurface(drv, display,
_eglLinkSurface(oldReadSurface, dpy));
}
if (!_eglIsContextLinked(oldContext)) {
/* make sure we don't try to rebind a deleted context */
if (ctx == oldContext) {
ctx = NULL;
}
/* really delete context now */
drv->API.DestroyContext(drv, dpy, _eglGetContextHandle(oldContext));
assert(ctx != oldContext);
drv->API.DestroyContext(drv, display,
_eglLinkContext(oldContext, dpy));
}
}
/* build new bindings */
if (ctx) {
/* check read/draw again, in case we deleted them above */
if (draw == NULL || read == NULL) {
_eglError(EGL_BAD_MATCH, "eglMakeCurrent");
return EGL_FALSE;
}
t->CurrentContexts[apiIndex] = ctx;
ctx->Binding = t;
ctx->DrawSurface = draw;
ctx->ReadSurface = read;
ctx->Binding = t;
draw->Binding = ctx;
read->Binding = ctx;
t->CurrentContexts[apiIndex] = ctx;
}
else {
t->CurrentContexts[apiIndex] = NULL;
}
return EGL_TRUE;