Bug 1438551 - Don't discard the back buffer when we reuse the front buffer. r?nical draft
authorRyan Hunt <rhunt@eqrion.net>
Tue, 10 Apr 2018 09:27:09 -0500
changeset 781717 588d6d81a8cda8b0cf8a3a64b0b8bbccad7eeb5b
parent 781354 ef75615080ea4aa0bf248e4cbe8f9a1a0906f667
child 781718 ac150fad072c10bc832b84dfb5ebb9b91f515170
push id106388
push userbmo:rhunt@eqrion.net
push dateFri, 13 Apr 2018 14:19:25 +0000
reviewersnical
bugs1438551
milestone61.0a1
Bug 1438551 - Don't discard the back buffer when we reuse the front buffer. r?nical It can happen often where we reuse the front buffer for a long paint, and then the next frame we see that it is still locked, and need to allocate a new buffer from the texture pool. If this happens we don't need to repaint the new buffer because the old buffer is still around, but we do need to copy it over and upload it to texture sources. It seems better to just hold onto the back buffer and let it accumulate more invalid regions. MozReview-Commit-ID: 2DQjwAX7ZmM
gfx/layers/client/TiledContentClient.cpp
gfx/thebes/gfxPrefs.h
modules/libpref/init/all.js
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -682,19 +682,25 @@ TileClient::GetBackBuffer(CompositableCl
   }
 
   // Try to re-use the front-buffer if possible
   if (mFrontBuffer &&
       mFrontBuffer->HasIntermediateBuffer() &&
       !mFrontBuffer->IsReadLocked() &&
       (aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA || (
         mFrontBufferOnWhite && !mFrontBufferOnWhite->IsReadLocked()))) {
-    // If we had a backbuffer we no longer care about it since we'll
-    // re-use the front buffer.
-    DiscardBackBuffer();
+    // If we had a backbuffer we no longer need it since we can re-use the
+    // front buffer here. It can be worth it to hold on to the back buffer
+    // so we don't need to pay the cost of initializing a new back buffer
+    // later (copying pixels and texture upload). But this could increase
+    // our memory usage and lead to OOM more frequently from spikes in usage,
+    // so we have this behavior behind a pref.
+    if (!gfxPrefs::LayersTileRetainBackBuffer()) {
+      DiscardBackBuffer();
+    }
     Flip();
   } else {
     if (!mBackBuffer || mBackBuffer->IsReadLocked()) {
       mBackBuffer.Set(this,
         CreateBackBufferTexture(mBackBuffer, aCompositable, mAllocator)
       );
       if (!mBackBuffer) {
         DiscardBackBuffer();
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -628,16 +628,17 @@ private:
   // they are often the same size as the screen, especially for width.
   DECL_GFX_PREF(Once, "layers.tile-width",                     LayersTileWidth, int32_t, 256);
   DECL_GFX_PREF(Once, "layers.tile-height",                    LayersTileHeight, int32_t, 256);
   DECL_GFX_PREF(Once, "layers.tile-initial-pool-size",         LayersTileInitialPoolSize, uint32_t, (uint32_t)50);
   DECL_GFX_PREF(Once, "layers.tile-pool-unused-size",          LayersTilePoolUnusedSize, uint32_t, (uint32_t)10);
   DECL_GFX_PREF(Once, "layers.tile-pool-shrink-timeout",       LayersTilePoolShrinkTimeout, uint32_t, (uint32_t)50);
   DECL_GFX_PREF(Once, "layers.tile-pool-clear-timeout",        LayersTilePoolClearTimeout, uint32_t, (uint32_t)5000);
   DECL_GFX_PREF(Once, "layers.tiles.adjust",                   LayersTilesAdjust, bool, true);
+  DECL_GFX_PREF(Live, "layers.tiles.retain-back-buffer",       LayersTileRetainBackBuffer, bool, true);
   DECL_GFX_PREF(Once, "layers.tiles.edge-padding",             TileEdgePaddingEnabled, bool, true);
   DECL_GFX_PREF(Live, "layers.tiles.fade-in.enabled",          LayerTileFadeInEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.tiles.fade-in.duration-ms",      LayerTileFadeInDuration, uint32_t, 250);
   DECL_GFX_PREF(Live, "layers.transaction.warning-ms",         LayerTransactionWarning, uint32_t, 200);
   DECL_GFX_PREF(Once, "layers.uniformity-info",                UniformityInfo, bool, false);
   DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces",   UseImageOffscreenSurfaces, bool, true);
   DECL_GFX_PREF(Live, "layers.draw-mask-debug",                DrawMaskLayer, bool, false);
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4830,16 +4830,17 @@ pref("layers.draw-borders", false);
 pref("layers.draw-tile-borders", false);
 pref("layers.draw-bigimage-borders", false);
 pref("layers.enable-tiles", false);
 pref("layers.single-tile.enabled", true);
 pref("layers.low-precision-buffer", false);
 pref("layers.progressive-paint", false);
 pref("layers.tile-width", 256);
 pref("layers.tile-height", 256);
+pref("layers.tiles.retain-back-buffer", true);
 pref("layers.child-process-shutdown", true);
 // Max number of layers per container. See Overwrite in mobile prefs.
 pref("layers.max-active", -1);
 // If this is set the tile size will only be treated as a suggestion.
 // On B2G we will round this to the stride of the underlying allocation.
 // On any platform we may later use the screen size and ignore
 // tile-width/tile-height entirely. Its recommended to turn this off
 // if you change the tile size.