EGL: Ensure surfaces are disconnected when destroyed

When eglDestroySurface is called, remove all references to the surface
in all contexts. This ensures that the surface is disconnected
immediately.

Bug 27455025

Change-Id: I0edaf039d320dc40122657db32abdc418665841a
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index e7703d8..943906f 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -603,6 +603,7 @@
     EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
     if (result == EGL_TRUE) {
         _s.terminate();
+        dp->removeSurface(surface);
     }
     return result;
 }
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 6a9d7b6..d849693 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -89,6 +89,31 @@
     return false;
 }
 
+void egl_display_t::addContext(egl_context_t* context) {
+    Mutex::Autolock _l(lock);
+    contexts.add(context);
+}
+
+void egl_display_t::removeContext(egl_context_t* context) {
+    Mutex::Autolock _l(lock);
+    contexts.remove(context);
+}
+
+void egl_display_t::removeSurface(EGLSurface surface) const {
+    Mutex::Autolock _l(lock);
+    for (size_t i = 0; i < contexts.size(); i++) {
+        egl_context_t* context = contexts[i];
+        if (context->read == surface) {
+            SurfaceRef _r(get_surface(context->read));
+            _r.release();
+        }
+        if (context->draw == surface) {
+            SurfaceRef _d(get_surface(context->draw));
+            _d.release();
+        }
+    }
+}
+
 EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
     if (uintptr_t(disp) >= NUM_DISPLAYS)
         return NULL;
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 2d86295..0ede705 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -68,6 +68,13 @@
     // add reference to this object. returns true if this is a valid object.
     bool getObject(egl_object_t* object) const;
 
+    // add context to this display's list
+    void addContext(egl_context_t* context);
+    // remove context from this display's list
+    void removeContext(egl_context_t* context);
+    // search for surface on all contexts and remove the references
+    void removeSurface(EGLSurface surface) const;
+
     // These notifications allow the display to keep track of how many window
     // surfaces exist, which it uses to decide whether to hibernate the
     // underlying EGL implementation. They can be called by any thread without
@@ -135,6 +142,7 @@
     mutable Mutex                       lock, refLock;
     mutable Condition                   refCond;
             SortedVector<egl_object_t*> objects;
+            SortedVector<egl_context_t*> contexts;
             String8 mVendorString;
             String8 mVersionString;
             String8 mClientApiString;
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 918faa8..8859387 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -91,6 +91,12 @@
         egl_connection_t const* cnx, int version) :
     egl_object_t(get_display_nowake(dpy)), dpy(dpy), context(context),
             config(config), read(0), draw(0), cnx(cnx), version(version) {
+    get_display_nowake(dpy)->addContext(this);
+}
+
+void egl_context_t::terminate() {
+    display->removeContext(this);
+    egl_object_t::terminate();
 }
 
 void egl_context_t::onLooseCurrent() {
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 17a8304..8268900 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -40,11 +40,12 @@
 class egl_display_t;
 
 class egl_object_t {
-    egl_display_t *display;
     mutable volatile int32_t count;
 
 protected:
     virtual ~egl_object_t();
+    virtual void terminate();
+    egl_display_t *display;
 
 public:
     egl_object_t(egl_display_t* display);
@@ -55,7 +56,6 @@
     inline egl_display_t* getDisplay() const { return display; }
 
 private:
-    void terminate();
     static bool get(egl_display_t const* display, egl_object_t* object);
 
 public:
@@ -143,6 +143,7 @@
 class egl_context_t: public egl_object_t {
 protected:
     ~egl_context_t() {}
+    void terminate() override;
 public:
     typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;