Only cache framebuffers for internal displays for drawLayers.
Currently SkiaGlRenderEngine leaks memory when virtual displays are
created and destroyed because their output buffers are cached into a
texture and then never evicted.
The simplest workaround which is implemented in this patch is to never
cache framebuffers for virtual displays; we only cache when driving
internal displays.
On phones, there is usually one primary internal display and that
display is never destroyed, so this assumption is safe for the majority
of phone form factors. In the very near future we should remove this
assumption by changing the RenderEngine interface to take in a struct
that manages GPU textures on creation and destruction so that
SurfaceFlinger can maintain its own cached set, but that change is
longer than a few lines of code, which motivates this patch.
Bug: 178539829
Test: builds, boots
Change-Id: I8e501d297090b6f5056a0b0ead598f85bb4b9f07
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 4f99495..3907ac5 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -989,9 +989,16 @@
});
const nsecs_t renderEngineStart = systemTime();
+ // Only use the framebuffer cache when rendering to an internal display
+ // TODO(b/173560331): This is only to help mitigate memory leaks from virtual displays because
+ // right now we don't have a concrete eviction policy for output buffers: GLESRenderEngine
+ // bounds its framebuffer cache but Skia RenderEngine has no current policy. The best fix is
+ // probably to encapsulate the output buffer into a structure that dispatches resource cleanup
+ // over to RenderEngine, in which case this flag can be removed from the drawLayers interface.
+ const bool useFramebufferCache = outputState.layerStackInternal;
status_t status =
renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buf,
- /*useFramebufferCache=*/true, std::move(fd), &readyFence);
+ useFramebufferCache, std::move(fd), &readyFence);
if (status != NO_ERROR && mClientCompositionRequestCache) {
// If rendering was not successful, remove the request from the cache.