egl: Make eglMakeCurrent more robust.
authorChia-I Wu <olvaffe@gmail.com>
Mon, 3 Aug 2009 17:35:14 +0000 (11:35 -0600)
committerBrian Paul <brianp@vmware.com>
Mon, 3 Aug 2009 17:35:14 +0000 (11:35 -0600)
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>
src/egl/main/eglcontext.c

index f8d5687f87c120d22813b37655d2b65c49994f2e..88de60d69bb7b1fd11403b1306fe8c2686a5a70a 100644 (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) {
+      /* 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;