From 8cdc6c66f9d8ede00d02108070d269d3aca8b130 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Mon, 3 Aug 2009 11:35:14 -0600 Subject: 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 --- src/egl/main/eglcontext.c | 98 ++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c index f8d5687..88de60d 100644 --- a/src/egl/main/eglcontext.c +++ b/src/egl/main/eglcontext.c @@ -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) { + /* 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)) { - /* 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); + assert(draw != oldDrawSurface && read != oldDrawSurface); + drv->API.DestroySurface(drv, display, + _eglLinkSurface(oldDrawSurface, dpy)); } - } - 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 (oldReadSurface != oldDrawSurface && + !_eglIsSurfaceLinked(oldReadSurface)) { + assert(draw != oldReadSurface && read != oldReadSurface); + drv->API.DestroySurface(drv, display, + _eglLinkSurface(oldReadSurface, dpy)); } - } - if (oldContext != NULL) { - oldContext->Binding = NULL; 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; -- cgit v1.1