Implemented semantics for eglDestroySurface when surface is current on thread.

The spec has this to say.

"
All resources associated with surface which were allocated by EGL are marked for deletion as soon as possible. If surface is current to any thread (see section 3.7.3), resources are not actually released while the surface remains current. Future references to surface remain valid only so long as it is current; it will be destroyed, and all future references to it will become invalid, as soon as any otherwise valid eglMakeCurrent call is made from the thread it is bound to."
Review URL: http://codereview.appspot.com/4449064

git-svn-id: https://angleproject.googlecode.com/svn/trunk@632 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/common/version.h b/src/common/version.h
index a3c7335..658d674 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -1,7 +1,7 @@
 #define MAJOR_VERSION 0
 #define MINOR_VERSION 0
 #define BUILD_VERSION 0
-#define BUILD_REVISION 629
+#define BUILD_REVISION 632
 
 #define STRINGIFY(x) #x
 #define MACRO_STRINGIFY(x) STRINGIFY(x)
diff --git a/src/libEGL/Display.cpp b/src/libEGL/Display.cpp
index 02d2e30..37761f1 100644
--- a/src/libEGL/Display.cpp
+++ b/src/libEGL/Display.cpp
@@ -589,8 +589,15 @@
 
 void Display::destroySurface(egl::Surface *surface)
 {
-    delete surface;
-    mSurfaceSet.erase(surface);
+    if (surface == egl::getCurrentDrawSurface() || surface == egl::getCurrentReadSurface())
+    {
+        surface->setPendingDestroy();
+    }
+    else
+    {
+        delete surface;
+        mSurfaceSet.erase(surface);
+    }
 }
 
 void Display::destroyContext(gl::Context *context)
@@ -624,7 +631,7 @@
 
 bool Display::isValidSurface(egl::Surface *surface)
 {
-    return mSurfaceSet.find(surface) != mSurfaceSet.end();
+    return mSurfaceSet.find(surface) != mSurfaceSet.end() && !surface->isPendingDestroy();
 }
 
 bool Display::hasExistingWindowSurface(HWND window)
diff --git a/src/libEGL/Surface.cpp b/src/libEGL/Surface.cpp
index cf4350f..91c9b41 100644
--- a/src/libEGL/Surface.cpp
+++ b/src/libEGL/Surface.cpp
@@ -38,6 +38,8 @@
     mSwapInterval = -1;
     setSwapInterval(1);
 
+    mIsPendingDestroy = false;
+
     subclassWindow();
     resetSwapChain();
 }
@@ -61,6 +63,8 @@
     mSwapInterval = -1;
     setSwapInterval(1);
 
+    mIsPendingDestroy = false;
+
     resetSwapChain(width, height);
 }
 
@@ -412,4 +416,13 @@
 {
     return mConfig->mRenderTargetFormat;
 }
+
+void Surface::setPendingDestroy() {
+    mIsPendingDestroy = true;
+}
+
+bool Surface::isPendingDestroy() const {
+    return mIsPendingDestroy;
+}
+
 }
diff --git a/src/libEGL/Surface.h b/src/libEGL/Surface.h
index 371badb..ba5b1ec 100644
--- a/src/libEGL/Surface.h
+++ b/src/libEGL/Surface.h
@@ -60,6 +60,9 @@
     virtual void setBoundTexture(gl::Texture2D *texture);
     virtual gl::Texture2D *getBoundTexture() const;
 
+    void setPendingDestroy();
+    bool isPendingDestroy() const;
+
 private:
     DISALLOW_COPY_AND_ASSIGN(Surface);
 
@@ -70,6 +73,7 @@
     IDirect3DTexture9* mOffscreenTexture;
 
     HANDLE mShareHandle;
+    bool mIsPendingDestroy;
 
     void subclassWindow();
     void unsubclassWindow();
diff --git a/src/libEGL/libEGL.cpp b/src/libEGL/libEGL.cpp
index 607db3d..84541bb 100644
--- a/src/libEGL/libEGL.cpp
+++ b/src/libEGL/libEGL.cpp
@@ -17,7 +17,7 @@
 #include "libEGL/Display.h"
 
 
-bool validate(egl::Display *display)
+bool validateDisplay(egl::Display *display)
 {
     if (display == EGL_NO_DISPLAY)
     {
@@ -32,9 +32,9 @@
     return true;
 }
 
-bool validate(egl::Display *display, EGLConfig config)
+bool validateConfig(egl::Display *display, EGLConfig config)
 {
-    if (!validate(display))
+    if (!validateDisplay(display))
     {
         return false;
     }
@@ -47,9 +47,9 @@
     return true;
 }
 
-bool validate(egl::Display *display, gl::Context *context)
+bool validateContext(egl::Display *display, gl::Context *context)
 {
-    if (!validate(display))
+    if (!validateDisplay(display))
     {
         return false;
     }
@@ -62,9 +62,9 @@
     return true;
 }
 
-bool validate(egl::Display *display, egl::Surface *surface)
+bool validateSurface(egl::Display *display, egl::Surface *surface)
 {
-    if (!validate(display))
+    if (!validateDisplay(display))
     {
         return false;
     }
@@ -185,7 +185,7 @@
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display))
+        if (!validateDisplay(display))
         {
             return NULL;
         }
@@ -222,7 +222,7 @@
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display))
+        if (!validateDisplay(display))
         {
             return EGL_FALSE;
         }
@@ -259,7 +259,7 @@
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display))
+        if (!validateDisplay(display))
         {
             return EGL_FALSE;
         }
@@ -297,7 +297,7 @@
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display, config))
+        if (!validateConfig(display, config))
         {
             return EGL_FALSE;
         }
@@ -326,7 +326,7 @@
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display, config))
+        if (!validateConfig(display, config))
         {
             return EGL_NO_SURFACE;
         }
@@ -357,7 +357,7 @@
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display, config))
+        if (!validateConfig(display, config))
         {
             return EGL_NO_SURFACE;
         }
@@ -381,7 +381,7 @@
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display, config))
+        if (!validateConfig(display, config))
         {
             return EGL_NO_SURFACE;
         }
@@ -405,8 +405,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
+        egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
 
-        if (!validate(display))
+        if (!validateSurface(display, eglSurface))
         {
             return EGL_FALSE;
         }
@@ -436,8 +437,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
+        egl::Surface *eglSurface = (egl::Surface*)surface;
 
-        if (!validate(display))
+        if (!validateSurface(display, eglSurface))
         {
             return EGL_FALSE;
         }
@@ -447,8 +449,6 @@
             return error(EGL_BAD_SURFACE, EGL_FALSE);
         }
 
-        egl::Surface *eglSurface = (egl::Surface*)surface;
-
         switch (attribute)
         {
           case EGL_VG_ALPHA_FORMAT:
@@ -521,8 +521,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
+        egl::Surface *eglSurface = (egl::Surface*)surface;
 
-        if (!validate(display))
+        if (!validateSurface(display, eglSurface))
         {
             return EGL_FALSE;
         }
@@ -532,8 +533,6 @@
             return error(EGL_BAD_SURFACE, EGL_FALSE);
         }
 
-        egl::Surface *eglSurface = (egl::Surface*)surface;
-
         switch (attribute)
         {
           case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
@@ -646,7 +645,7 @@
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display, config))
+        if (!validateConfig(display, config))
         {
             return EGL_NO_SURFACE;
         }
@@ -671,8 +670,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
+        egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
 
-        if (!validate(display))
+        if (!validateSurface(display, eglSurface))
         {
             return EGL_FALSE;
         }
@@ -696,9 +696,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
-        egl::Surface *surf = static_cast<egl::Surface*>(surface);
+        egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
 
-        if (!validate(display))
+        if (!validateSurface(display, eglSurface))
         {
             return EGL_FALSE;
         }
@@ -708,22 +708,22 @@
             return error(EGL_BAD_PARAMETER, EGL_FALSE);
         }
 
-        if (surface == EGL_NO_SURFACE || surf->getWindowHandle())
+        if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
         {
             return error(EGL_BAD_SURFACE, EGL_FALSE);
         }
 
-        if (surf->getBoundTexture())
+        if (eglSurface->getBoundTexture())
         {
             return error(EGL_BAD_ACCESS, EGL_FALSE);
         }
 
-        if (surf->getTextureFormat() == EGL_NO_TEXTURE)
+        if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
         {
             return error(EGL_BAD_MATCH, EGL_FALSE);
         }
 
-        glBindTexImage(surf);
+        glBindTexImage(eglSurface);
 
         return success(EGL_TRUE);
     }
@@ -742,9 +742,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
-        egl::Surface *surf = static_cast<egl::Surface*>(surface);
+        egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
 
-        if (!validate(display))
+        if (!validateSurface(display, eglSurface))
         {
             return EGL_FALSE;
         }
@@ -754,17 +754,17 @@
             return error(EGL_BAD_PARAMETER, EGL_FALSE);
         }
 
-        if (surface == EGL_NO_SURFACE || surf->getWindowHandle())
+        if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
         {
             return error(EGL_BAD_SURFACE, EGL_FALSE);
         }
 
-        if (surf->getTextureFormat() == EGL_NO_TEXTURE)
+        if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
         {
             return error(EGL_BAD_MATCH, EGL_FALSE);
         }
 
-        gl::Texture2D *texture = surf->getBoundTexture();
+        gl::Texture2D *texture = eglSurface->getBoundTexture();
 
         if (texture)
         {
@@ -789,7 +789,7 @@
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display))
+        if (!validateDisplay(display))
         {
             return EGL_FALSE;
         }
@@ -844,7 +844,7 @@
 
         egl::Display *display = static_cast<egl::Display*>(dpy);
 
-        if (!validate(display, config))
+        if (!validateConfig(display, config))
         {
             return EGL_NO_CONTEXT;
         }
@@ -868,8 +868,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
+        gl::Context *context = static_cast<gl::Context*>(ctx);
 
-        if (!validate(display))
+        if (!validateContext(display, context))
         {
             return EGL_FALSE;
         }
@@ -879,7 +880,7 @@
             return error(EGL_BAD_CONTEXT, EGL_FALSE);
         }
 
-        display->destroyContext((gl::Context*)ctx);
+        display->destroyContext(context);
 
         return success(EGL_TRUE);
     }
@@ -907,13 +908,13 @@
             return error(EGL_CONTEXT_LOST, EGL_FALSE);
         }
 
-        if (ctx != EGL_NO_CONTEXT && !validate(display, context))
+        if (ctx != EGL_NO_CONTEXT && !validateContext(display, context))
         {
             return EGL_FALSE;
         }
 
-        if ((draw != EGL_NO_SURFACE && !validate(display, static_cast<egl::Surface*>(draw))) ||
-            (read != EGL_NO_SURFACE && !validate(display, static_cast<egl::Surface*>(read))))
+        if ((draw != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(draw))) ||
+            (read != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(read))))
         {
             return EGL_FALSE;
         }
@@ -923,12 +924,27 @@
             UNIMPLEMENTED();   // FIXME
         }
 
+        egl::Surface* previousDraw = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
+        egl::Surface* previousRead = static_cast<egl::Surface*>(egl::getCurrentReadSurface());
+
         egl::setCurrentDisplay(dpy);
         egl::setCurrentDrawSurface(draw);
         egl::setCurrentReadSurface(read);
 
         glMakeCurrent(context, display, static_cast<egl::Surface*>(draw));
 
+        // If the previous surfaces are still current, this might just flag
+        // them as pending destruction again, deferring destruction to a future
+        // eglMakeCurrent or eglTerminate call.
+        if (previousDraw && previousDraw->isPendingDestroy())
+        {
+            eglDestroySurface(dpy, previousDraw);
+        }
+        if (previousRead && previousRead != previousDraw && previousRead->isPendingDestroy())
+        {
+            eglDestroySurface(dpy, previousRead);
+        }
+
         return success(EGL_TRUE);
     }
     catch(std::bad_alloc&)
@@ -1012,8 +1028,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
+        gl::Context *context = static_cast<gl::Context*>(ctx);
 
-        if (!validate(display))
+        if (!validateContext(display, context))
         {
             return EGL_FALSE;
         }
@@ -1073,8 +1090,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
+        egl::Surface *eglSurface = (egl::Surface*)surface;
 
-        if (!validate(display))
+        if (!validateSurface(display, eglSurface))
         {
             return EGL_FALSE;
         }
@@ -1084,8 +1102,6 @@
             return error(EGL_BAD_SURFACE, EGL_FALSE);
         }
 
-        egl::Surface *eglSurface = (egl::Surface*)surface;
-
         if (eglSurface->swap())
         {
             return success(EGL_TRUE);
@@ -1106,8 +1122,9 @@
     try
     {
         egl::Display *display = static_cast<egl::Display*>(dpy);
+        egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
 
-        if (!validate(display))
+        if (!validateSurface(display, eglSurface))
         {
             return EGL_FALSE;
         }