[RenderEngine] Rebind output texture when unbinding framebuffer
Without this patch, once drawLayers() completes we'd hold onto the
backing image data longer than intended since it's bound to sibling
texture. This would cause screenshot buffers to be live for longer than
intended. This patch rebinds the framebuffer's output texture to a dummy
buffer so that we can free memory sooner.
We perform this rebind on the main thread in
SurfaceFlinger::postComposition, to minimize the amount of expected time
we steal for composition due to this cleanup. We also only do this
cleanup if the most recent draw fence had fired, since the driver will
need to wait for GPU work to complete before freeing resources which can
kill performance.
Bug: 140158384
Test: screencap and check dumpsys
Test: systrace when during screen rotation
Test: systrace when toggling GPU composition on and off
Test: librenderengine_test, libcompositionengine_test
Change-Id: I0aa39e62f03a09f6db000c2abdbb1d0711127fc3
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index da87092..df711d2 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -897,13 +897,32 @@
return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
}
-void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
+void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /*framebuffer*/) {
ATRACE_CALL();
// back to main framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
+bool GLESRenderEngine::cleanupPostRender() {
+ ATRACE_CALL();
+
+ if (mPriorResourcesCleaned ||
+ (mLastDrawFence != nullptr && mLastDrawFence->getStatus() != Fence::Status::Signaled)) {
+ // If we don't have a prior frame needing cleanup, then don't do anything.
+ return false;
+ }
+
+ // Bind the texture to dummy data so that backing image data can be freed.
+ GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(getFramebufferForDrawing());
+ glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer);
+ // Release the cached fence here, so that we don't churn reallocations when
+ // we could no-op repeated calls of this method instead.
+ mLastDrawFence = nullptr;
+ mPriorResourcesCleaned = true;
+ return true;
+}
+
void GLESRenderEngine::checkErrors() const {
checkErrors(nullptr);
}
@@ -1193,7 +1212,13 @@
// us bad parameters, or we messed up our shader generation).
return INVALID_OPERATION;
}
+ mLastDrawFence = nullptr;
+ } else {
+ // The caller takes ownership of drawFence, so we need to duplicate the
+ // fd here.
+ mLastDrawFence = new Fence(dup(drawFence->get()));
}
+ mPriorResourcesCleaned = false;
checkErrors();
return NO_ERROR;