Call eglReleaseThread() in ~RenderThread()
... to ensure EGL resources are fully cleaned up. Prior to this change,
running Cuttlefish with Gfxstream on Nvidia would leak file descriptors
and memory every time an app was opened and closed.
Bug: b/189879393
Test: `launch_cvd --gpu_mode=gfxstream` and open+close phone repeatedly
Change-Id: I1e8f3008cca2dbd7ab815104903da5094c3e865f
diff --git a/stream-servers/RenderThread.cpp b/stream-servers/RenderThread.cpp
index 85860c3..56557aa 100644
--- a/stream-servers/RenderThread.cpp
+++ b/stream-servers/RenderThread.cpp
@@ -112,7 +112,9 @@
}
}
-
+// Note: the RenderThread destructor might be called from a different thread
+// than from RenderThread::main() so thread specific cleanup likely belongs at
+// the end of RenderThread::main().
RenderThread::~RenderThread() = default;
void RenderThread::pausePreSnapshot() {
@@ -519,6 +521,10 @@
FrameBuffer::getFB()->drainRenderContext();
}
+ if (!s_egl.eglReleaseThread()) {
+ DBG("Error: RenderThread @%p failed to eglReleaseThread()\n", this);
+ }
+
setFinished();
DBG("Exited a RenderThread @%p\n", this);
diff --git a/stream-servers/glestranslator/EGL/EglDisplay.h b/stream-servers/glestranslator/EGL/EglDisplay.h
index 51975dd..16778c7 100644
--- a/stream-servers/glestranslator/EGL/EglDisplay.h
+++ b/stream-servers/glestranslator/EGL/EglDisplay.h
@@ -89,6 +89,10 @@
return dispContext->nativeType()->getNative();
}
+ EGLBoolean releaseThread() {
+ return nativeType()->releaseThread();
+ }
+
// Write up to |config_size| EGLConfig values into the |configs| array.
// Return the number if values written.
int getConfigs(EGLConfig* configs,int config_size) const;
diff --git a/stream-servers/glestranslator/EGL/EglImp.cpp b/stream-servers/glestranslator/EGL/EglImp.cpp
index d89e219..ca56e63 100644
--- a/stream-servers/glestranslator/EGL/EglImp.cpp
+++ b/stream-servers/glestranslator/EGL/EglImp.cpp
@@ -1331,7 +1331,10 @@
MEM_TRACE("EMUGL");
ThreadInfo* thread = getThreadInfo();
EglDisplay* dpy = static_cast<EglDisplay*>(thread->eglDisplay);
- return translator::egl::eglMakeCurrent(dpy,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT);
+ if (!translator::egl::eglMakeCurrent(dpy,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT)) {
+ return EGL_FALSE;
+ }
+ return dpy->releaseThread();
}
EGLAPI void* EGLAPIENTRY
diff --git a/stream-servers/glestranslator/EGL/EglOsApi.h b/stream-servers/glestranslator/EGL/EglOsApi.h
index 0ab6c51..cd073f3 100644
--- a/stream-servers/glestranslator/EGL/EglOsApi.h
+++ b/stream-servers/glestranslator/EGL/EglOsApi.h
@@ -206,6 +206,8 @@
virtual void swapBuffers(Surface* srfc) = 0;
+ virtual EGLBoolean releaseThread() { return EGL_TRUE; }
+
DISALLOW_COPY_AND_ASSIGN(Display);
};
diff --git a/stream-servers/glestranslator/EGL/EglOsApi_egl.cpp b/stream-servers/glestranslator/EGL/EglOsApi_egl.cpp
index 1244433..aa5222d 100644
--- a/stream-servers/glestranslator/EGL/EglOsApi_egl.cpp
+++ b/stream-servers/glestranslator/EGL/EglOsApi_egl.cpp
@@ -124,6 +124,7 @@
EGLContext ctx, EGLenum target, EGLClientBuffer buffer, \
const EGLint *attrib_list)) \
X(EGLBoolean, eglDestroyImage, (EGLDisplay dpy, EGLImage image)) \
+ X(EGLBoolean, eglReleaseThread, (void)) \
namespace {
using namespace EglOS;
@@ -293,6 +294,7 @@
Surface* createWindowSurface(PixelFormat* pf, EGLNativeWindowType win);
bool releasePbuffer(Surface* pb);
bool makeCurrent(Surface* read, Surface* draw, Context* context);
+ EGLBoolean releaseThread();
void swapBuffers(Surface* srfc);
bool isValidNativeWin(Surface* win);
bool isValidNativeWin(EGLNativeWindowType win);
@@ -665,6 +667,11 @@
mDispatcher.eglSwapBuffers(mDisplay, sfc->getHndl());
}
+EGLBoolean EglOsEglDisplay::releaseThread() {
+ D("%s\n", __FUNCTION__);
+ return mDispatcher.eglReleaseThread();
+}
+
bool EglOsEglDisplay::isValidNativeWin(Surface* win) {
if (!win)
return false;