egl: Use reference counting to replace IsLinked or IsBound.
authorChia-I Wu <olv@lunarg.com>
Sat, 23 Oct 2010 04:52:26 +0000 (12:52 +0800)
committerChia-I Wu <olv@lunarg.com>
Sat, 23 Oct 2010 07:26:28 +0000 (15:26 +0800)
Remove all _egl<Res>IsLinked and _egl<Res>IsBound.  Update
_eglBindContext and drivers to do reference counting.

src/egl/drivers/dri2/egl_dri2.c
src/egl/drivers/glx/egl_glx.c
src/egl/main/eglapi.c
src/egl/main/eglcontext.c
src/egl/main/eglcontext.h
src/egl/main/eglimage.h
src/egl/main/eglsurface.h
src/egl/main/eglsync.h
src/gallium/state_trackers/egl/common/egl_g3d_api.c

index 75aa29f55b970a136ed7cb8e7a1cadd021c55dd3..a5f95b944c55039b7a2aeeea82339f1ef58dc82c 100644 (file)
@@ -1160,7 +1160,7 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
 
    (void) drv;
 
-   if (_eglIsSurfaceBound(surf))
+   if (!_eglPutSurface(surf))
       return EGL_TRUE;
 
    (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
@@ -1187,11 +1187,13 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
    struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
    struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
    struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+   _EGLContext *old_ctx;
+   _EGLSurface *old_dsurf, *old_rsurf;
    __DRIdrawable *ddraw, *rdraw;
    __DRIcontext *cctx;
 
-   /* bind the new context and return the "orphaned" one */
-   if (!_eglBindContext(&ctx, &dsurf, &rsurf))
+   /* make new bindings */
+   if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
       return EGL_FALSE;
 
    /* flush before context switch */
@@ -1204,16 +1206,29 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
 
    if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
        dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
-      if (dsurf && !_eglIsSurfaceLinked(dsurf))
-        dri2_destroy_surface(drv, disp, dsurf);
-      if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(dsurf))
-        dri2_destroy_surface(drv, disp, rsurf);
-      if (ctx != NULL && !_eglIsContextLinked(ctx))
-        dri2_dpy->core->unbindContext(dri2_egl_context(ctx)->dri_context);
+      dri2_destroy_surface(drv, disp, old_dsurf);
+      dri2_destroy_surface(drv, disp, old_rsurf);
+      if (old_ctx) {
+        dri2_dpy->core->unbindContext(dri2_egl_context(old_ctx)->dri_context);
+         /* no destroy? */
+         _eglPutContext(old_ctx);
+      }
 
       return EGL_TRUE;
    } else {
-      _eglBindContext(&ctx, &dsurf, &rsurf);
+      /* undo the previous _eglBindContext */
+      _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
+      assert(&dri2_ctx->base == ctx &&
+             &dri2_dsurf->base == dsurf &&
+             &dri2_rsurf->base == rsurf);
+
+      _eglPutSurface(dsurf);
+      _eglPutSurface(rsurf);
+      _eglPutContext(ctx);
+
+      _eglPutSurface(old_dsurf);
+      _eglPutSurface(old_rsurf);
+      _eglPutContext(old_ctx);
 
       return EGL_FALSE;
    }
index 256de57ed873c6d39e7223426bb828823aa27ba2..8ec7c48c50e4b82ca197fb459553c6ac22006e02 100644 (file)
@@ -677,14 +677,16 @@ GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
    struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
    struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
    struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
+   _EGLContext *old_ctx;
+   _EGLSurface *old_dsurf, *old_rsurf;
    GLXDrawable ddraw, rdraw;
    GLXContext cctx;
    EGLBoolean ret = EGL_FALSE;
 
    (void) drv;
 
-   /* bind the new context and return the "orphaned" one */
-   if (!_eglBindContext(&ctx, &dsurf, &rsurf))
+   /* make new bindings */
+   if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
       return EGL_FALSE;
 
    ddraw = (GLX_dsurf) ? GLX_dsurf->glx_drawable : None;
@@ -697,13 +699,27 @@ GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
       ret = glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx);
 
    if (ret) {
-      if (dsurf && !_eglIsSurfaceLinked(dsurf))
-         destroy_surface(disp, dsurf);
-      if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(rsurf))
-         destroy_surface(disp, rsurf);
+      if (_eglPutSurface(old_dsurf))
+         destroy_surface(disp, old_dsurf);
+      if (_eglPutSurface(old_rsurf))
+         destroy_surface(disp, old_rsurf);
+      /* no destroy? */
+      _eglPutContext(old_ctx);
    }
    else {
-      _eglBindContext(&ctx, &dsurf, &rsurf);
+      /* undo the previous _eglBindContext */
+      _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
+      assert(&GLX_ctx->Base == ctx &&
+             &GLX_dsurf->Base == dsurf &&
+             &GLX_rsurf->Base == rsurf);
+
+      _eglPutSurface(dsurf);
+      _eglPutSurface(rsurf);
+      _eglPutContext(ctx);
+
+      _eglPutSurface(old_dsurf);
+      _eglPutSurface(old_rsurf);
+      _eglPutContext(old_ctx);
    }
 
    return ret;
@@ -907,7 +923,7 @@ GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
 {
    (void) drv;
 
-   if (!_eglIsSurfaceBound(surf))
+   if (_eglPutSurface(surf))
       destroy_surface(disp, surf);
 
    return EGL_TRUE;
index 913ddd288bd06ed579d40d5ac1022afacb891017..efa9e97346b127e093429aa2d8731ecee120100b 100644 (file)
@@ -648,11 +648,12 @@ eglSwapInterval(EGLDisplay dpy, EGLint interval)
 
    _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
 
-   if (!ctx || !_eglIsContextLinked(ctx) || ctx->Resource.Display != disp)
+   if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
+       ctx->Resource.Display != disp)
       RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_FALSE);
 
    surf = ctx->DrawSurface;
-   if (!_eglIsSurfaceLinked(surf))
+   if (_eglGetSurfaceHandle(surf) == EGL_NO_SURFACE)
       RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
 
    ret = drv->API.SwapInterval(drv, disp, surf, interval);
@@ -673,7 +674,8 @@ eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
    _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv);
 
    /* surface must be bound to current context in EGL 1.4 */
-   if (!ctx || !_eglIsContextLinked(ctx) || surf != ctx->DrawSurface)
+   if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
+       surf != ctx->DrawSurface)
       RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
 
    ret = drv->API.SwapBuffers(drv, disp, surf);
@@ -714,7 +716,8 @@ eglWaitClient(void)
    _eglLockMutex(&disp->Mutex);
 
    /* let bad current context imply bad current surface */
-   if (!_eglIsContextLinked(ctx) || !_eglIsSurfaceLinked(ctx->DrawSurface))
+   if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
+       _eglGetSurfaceHandle(ctx->DrawSurface) == EGL_NO_SURFACE)
       RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
 
    /* a valid current context implies an initialized current display */
@@ -763,7 +766,8 @@ eglWaitNative(EGLint engine)
    _eglLockMutex(&disp->Mutex);
 
    /* let bad current context imply bad current surface */
-   if (!_eglIsContextLinked(ctx) || !_eglIsSurfaceLinked(ctx->DrawSurface))
+   if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
+       _eglGetSurfaceHandle(ctx->DrawSurface) == EGL_NO_SURFACE)
       RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
 
    /* a valid current context implies an initialized current display */
@@ -1437,7 +1441,8 @@ eglSwapBuffersRegionNOK(EGLDisplay dpy, EGLSurface surface,
       RETURN_EGL_EVAL(disp, EGL_FALSE);
 
    /* surface must be bound to current context in EGL 1.4 */
-   if (!ctx || !_eglIsContextLinked(ctx) || surf != ctx->DrawSurface)
+   if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
+       surf != ctx->DrawSurface)
       RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
 
    ret = drv->API.SwapBuffersRegionNOK(drv, disp, surf, numRects, rects);
index b4cc7439583e53984f62268a08d7ea088564f5b4..3266a7582494bd41a19d91e51a277204033de25e 100644 (file)
@@ -300,54 +300,65 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
 
 /**
  * Bind the context to the current thread and given surfaces.  Return the
- * "orphaned" context and surfaces.  Each argument is both input and output.
+ * previous bound context and surfaces.  The caller should unreference the
+ * returned context and surfaces.
+ *
+ * Making a second call with the resources returned by the first call
+ * unsurprisingly undoes the first call, except for the resouce reference
+ * counts.
  */
 EGLBoolean
-_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read)
+_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
+                _EGLContext **old_ctx,
+                _EGLSurface **old_draw, _EGLSurface **old_read)
 {
    _EGLThreadInfo *t = _eglGetCurrentThread();
-   _EGLContext *newCtx = *ctx, *oldCtx;
-   _EGLSurface *newDraw = *draw, *newRead = *read;
+   _EGLContext *prev_ctx;
+   _EGLSurface *prev_draw, *prev_read;
 
-   if (!_eglCheckMakeCurrent(newCtx, newDraw, newRead))
+   if (!_eglCheckMakeCurrent(ctx, draw, read))
       return EGL_FALSE;
 
+   /* increment refcounts before binding */
+   _eglGetContext(ctx);
+   _eglGetSurface(draw);
+   _eglGetSurface(read);
+
    /* bind the new context */
-   oldCtx = _eglBindContextToThread(newCtx, t);
+   prev_ctx = _eglBindContextToThread(ctx, t);
 
-   /* break old bindings */
-   if (oldCtx) {
-      *ctx = oldCtx;
-      *draw = oldCtx->DrawSurface;
-      *read = oldCtx->ReadSurface;
+   /* break previous bindings */
+   if (prev_ctx) {
+      prev_draw = prev_ctx->DrawSurface;
+      prev_read = prev_ctx->ReadSurface;
 
-      if (*draw)
-         (*draw)->CurrentContext = NULL;
-      if (*read)
-         (*read)->CurrentContext = NULL;
+      if (prev_draw)
+         prev_draw->CurrentContext = NULL;
+      if (prev_read)
+         prev_read->CurrentContext = NULL;
 
-      oldCtx->DrawSurface = NULL;
-      oldCtx->ReadSurface = NULL;
+      prev_ctx->DrawSurface = NULL;
+      prev_ctx->ReadSurface = NULL;
+   }
+   else {
+      prev_draw = prev_read = NULL;
    }
 
    /* establish new bindings */
-   if (newCtx) {
-      if (newDraw)
-         newDraw->CurrentContext = newCtx;
-      if (newRead)
-         newRead->CurrentContext = newCtx;
-
-      newCtx->DrawSurface = newDraw;
-      newCtx->ReadSurface = newRead;
+   if (ctx) {
+      if (draw)
+         draw->CurrentContext = ctx;
+      if (read)
+         read->CurrentContext = ctx;
+
+      ctx->DrawSurface = draw;
+      ctx->ReadSurface = read;
    }
 
-   /* an old context or surface is not orphaned if it is still bound */
-   if (*ctx == newCtx)
-      *ctx = NULL;
-   if (*draw == newDraw || *draw == newRead)
-      *draw = NULL;
-   if (*read == newDraw || *read == newRead)
-      *read = NULL;
+   assert(old_ctx && old_draw && old_read);
+   *old_ctx = prev_ctx;
+   *old_draw = prev_draw;
+   *old_read = prev_read;
 
    return EGL_TRUE;
 }
index 9c1e2184c640d887759ae3a1b0323a4a53b10b43..8cd0df173135bd69079541114619bf5dc13ad021 100644 (file)
@@ -39,7 +39,9 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLint att
 
 
 PUBLIC EGLBoolean
-_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read);
+_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
+                _EGLContext **old_ctx,
+                _EGLSurface **old_draw, _EGLSurface **old_read);
 
 
 /**
@@ -64,19 +66,6 @@ _eglPutContext(_EGLContext *ctx)
 }
 
 
-/**
- * Return true if the context is bound to a thread.
- *
- * The binding is considered a reference to the context.  Drivers should not
- * destroy a context when it is bound.
- */
-static INLINE EGLBoolean
-_eglIsContextBound(_EGLContext *ctx)
-{
-   return (ctx->Binding != NULL);
-}
-
-
 /**
  * Link a context to its display and return the handle of the link.
  * The handle can be passed to client directly.
@@ -126,18 +115,4 @@ _eglGetContextHandle(_EGLContext *ctx)
 }
 
 
-/**
- * Return true if the context is linked to a display.
- *
- * The link is considered a reference to the context (the display is owning the
- * context).  Drivers should not destroy a context when it is linked.
- */
-static INLINE EGLBoolean
-_eglIsContextLinked(_EGLContext *ctx)
-{
-   _EGLResource *res = (_EGLResource *) ctx;
-   return (res && _eglIsResourceLinked(res));
-}
-
-
 #endif /* EGLCONTEXT_INCLUDED */
index bdc325a7f33c4a2a15950e5754ff6a23b000d9da..adb939a9e02332944f8601d9a232d70fdc333217 100644 (file)
@@ -113,15 +113,4 @@ _eglGetImageHandle(_EGLImage *img)
 }
 
 
-/**
- * Return true if the image is linked to a display.
- */
-static INLINE EGLBoolean
-_eglIsImageLinked(_EGLImage *img)
-{
-   _EGLResource *res = (_EGLResource *) img;
-   return (res && _eglIsResourceLinked(res));
-}
-
-
 #endif /* EGLIMAGE_INCLUDED */
index b833258bf69d3ec7353092b2ae371f82fbeeaa0e..ef01b32ede3d1892ed54a86d08d80757e0bc6a46 100644 (file)
@@ -67,19 +67,6 @@ extern EGLBoolean
 _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval);
 
 
-/**
- * Return true if there is a context bound to the surface.
- *
- * The binding is considered a reference to the surface.  Drivers should not
- * destroy a surface when it is bound.
- */
-static INLINE EGLBoolean
-_eglIsSurfaceBound(_EGLSurface *surf)
-{
-   return (surf->CurrentContext != NULL);
-}
-
-
 /**
  * Increment reference count for the surface.
  */
@@ -151,18 +138,4 @@ _eglGetSurfaceHandle(_EGLSurface *surf)
 }
 
 
-/**
- * Return true if the surface is linked to a display.
- *
- * The link is considered a reference to the surface (the display is owning the
- * surface).  Drivers should not destroy a surface when it is linked.
- */
-static INLINE EGLBoolean
-_eglIsSurfaceLinked(_EGLSurface *surf)
-{
-   _EGLResource *res = (_EGLResource *) surf;
-   return (res && _eglIsResourceLinked(res));
-}
-
-
 #endif /* EGLSURFACE_INCLUDED */
index 97ae67cf866bbc5d36b2d33e1904e42d6c38fc76..a0025237e7aaa1e499f6c8b3ec2495c9f8316bd6 100644 (file)
@@ -103,20 +103,6 @@ _eglGetSyncHandle(_EGLSync *sync)
 }
 
 
-/**
- * Return true if the sync is linked to a display.
- *
- * The link is considered a reference to the sync (the display is owning the
- * sync).  Drivers should not destroy a sync when it is linked.
- */
-static INLINE EGLBoolean
-_eglIsSyncLinked(_EGLSync *sync)
-{
-   _EGLResource *res = (_EGLResource *) sync;
-   return (res && _eglIsResourceLinked(res));
-}
-
-
 #endif /* EGL_KHR_reusable_sync */
 
 
index 3bde39737ba2d7675c43d4a2850b582e3d57c4bb..c10245bb067a409671a8368ede4ae5e6eb9f4cd9 100644 (file)
@@ -160,7 +160,7 @@ destroy_context(_EGLDisplay *dpy, _EGLContext *ctx)
 static EGLBoolean
 egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
 {
-   if (!_eglIsContextBound(ctx))
+   if (_eglPutContext(ctx))
       destroy_context(dpy, ctx);
    return EGL_TRUE;
 }
@@ -433,7 +433,7 @@ destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf)
 static EGLBoolean
 egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
 {
-   if (!_eglIsSurfaceBound(surf))
+   if (_eglPutSurface(surf))
       destroy_surface(dpy, surf);
    return EGL_TRUE;
 }
@@ -446,13 +446,15 @@ egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
    struct egl_g3d_surface *gdraw = egl_g3d_surface(draw);
    struct egl_g3d_surface *gread = egl_g3d_surface(read);
    struct egl_g3d_context *old_gctx;
+   _EGLContext *old_ctx;
+   _EGLSurface *old_draw, *old_read;
    EGLBoolean ok = EGL_TRUE;
 
-   /* bind the new context and return the "orphaned" one */
-   if (!_eglBindContext(&ctx, &draw, &read))
+   /* make new bindings */
+   if (!_eglBindContext(ctx, draw, read, &old_ctx, &old_draw, &old_read))
       return EGL_FALSE;
-   old_gctx = egl_g3d_context(ctx);
 
+   old_gctx = egl_g3d_context(old_ctx);
    if (old_gctx) {
       /* flush old context */
       old_gctx->stctxi->flush(old_gctx->stctxi,
@@ -481,15 +483,33 @@ egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
    }
    else if (old_gctx) {
       ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL);
-      old_gctx->base.WindowRenderBuffer = EGL_NONE;
+      if (ok)
+         old_gctx->base.WindowRenderBuffer = EGL_NONE;
    }
 
-   if (ctx && !_eglIsContextLinked(ctx))
-      destroy_context(dpy, ctx);
-   if (draw && !_eglIsSurfaceLinked(draw))
-      destroy_surface(dpy, draw);
-   if (read && read != draw && !_eglIsSurfaceLinked(read))
-      destroy_surface(dpy, read);
+   if (ok) {
+      if (_eglPutContext(old_ctx))
+         destroy_context(dpy, old_ctx);
+      if (_eglPutSurface(old_draw))
+         destroy_surface(dpy, old_draw);
+      if (_eglPutSurface(old_read))
+         destroy_surface(dpy, old_read);
+   }
+   else {
+      /* undo the previous _eglBindContext */
+      _eglBindContext(old_ctx, old_draw, old_read, &ctx, &draw, &read);
+      assert(&gctx->base == ctx &&
+             &gdraw->base == draw &&
+             &gread->base == read);
+
+      _eglPutSurface(draw);
+      _eglPutSurface(read);
+      _eglPutContext(ctx);
+
+      _eglPutSurface(old_draw);
+      _eglPutSurface(old_read);
+      _eglPutContext(old_ctx);
+   }
 
    return ok;
 }