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;