Bug 1041744 - Don't crash if tile allocation fails. r=Bas, a=sledru
authorNicolas Silva <nsilva@mozilla.com>
Thu, 11 Sep 2014 13:52:17 +0200
changeset 224794 10ddaad98dfef14bf10fde64a7c4f7f19ca477bd
parent 224793 60c967fb8311fad437f5cf9907391dbed5cde0ec
child 224795 de1eed9ed4c2eed62c47ad727bb3bd8f7e6097f2
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, sledru
bugs1041744
milestone34.0a2
Bug 1041744 - Don't crash if tile allocation fails. r=Bas, a=sledru
gfx/layers/TiledLayerBuffer.h
gfx/layers/client/TiledContentClient.cpp
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -455,20 +455,23 @@ TiledLayerBuffer<Derived, Tile>::Update(
       if (tileDrawRegion.IsEmpty()) {
         // We have a tile but it doesn't hit the draw region
         // because we can reuse all of the content from the
         // previous buffer.
 #ifdef DEBUG
         int currTileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
         int currTileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
         int index = currTileX * mRetainedHeight + currTileY;
-        NS_ABORT_IF_FALSE(!newValidRegion.Intersects(tileRect) ||
-                          !IsPlaceholder(newRetainedTiles.
-                                         SafeElementAt(index, AsDerived().GetPlaceholderTile())),
-                          "If we don't draw a tile we shouldn't have a placeholder there.");
+        // If allocating a tile failed we can run into this assertion.
+        // Rendering is going to be glitchy but we don't want to crash.
+        NS_ASSERTION(!newValidRegion.Intersects(tileRect) ||
+                     !IsPlaceholder(newRetainedTiles.
+                                    SafeElementAt(index, AsDerived().GetPlaceholderTile())),
+                     "Unexpected placeholder tile");
+
 #endif
         y += height;
         continue;
       }
 
       int tileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
       int tileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
       int index = tileX * mRetainedHeight + tileY;
@@ -489,17 +492,17 @@ TiledLayerBuffer<Derived, Tile>::Update(
       }
 
       // We've done our best effort to recycle a tile but it can be null
       // in which case it's up to the derived class's ValidateTile()
       // implementation to allocate a new tile before drawing
       nsIntPoint tileOrigin(tileStartX, tileStartY);
       newTile = AsDerived().ValidateTile(newTile, nsIntPoint(tileStartX, tileStartY),
                                          tileDrawRegion);
-      NS_ABORT_IF_FALSE(!IsPlaceholder(newTile), "index out of range");
+      NS_ASSERTION(!IsPlaceholder(newTile), "Unexpected placeholder tile - failed to allocate?");
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
       printf_stderr("Store Validate tile %i, %i -> %i\n", tileStartX, tileStartY, index);
 #endif
       newRetainedTiles[index] = newTile;
 
       y += height;
     }
 
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -746,34 +746,44 @@ TileClient::GetBackBuffer(const nsIntReg
     DiscardBackBuffer();
     Flip();
     *aBackBufferOnWhite = mBackBufferOnWhite;
     return mBackBuffer;
   }
 
   if (!mBackBuffer ||
       mBackLock->GetReadCount() > 1) {
+
+    if (mBackLock) {
+      // Before we Replacing the lock by another one we need to unlock it!
+      mBackLock->ReadUnlock();
+    }
+
     if (mBackBuffer) {
       // Our current back-buffer is still locked by the compositor. This can occur
       // when the client is producing faster than the compositor can consume. In
       // this case we just want to drop it and not return it to the pool.
       pool->ReportClientLost();
       if (mBackBufferOnWhite) {
         pool->ReportClientLost();
       }
     }
     mBackBuffer.Set(this, pool->GetTextureClient());
-    if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
-      mBackBufferOnWhite = pool->GetTextureClient();
+    if (!mBackBuffer) {
+      return nullptr;
     }
 
-    if (mBackLock) {
-      // Before we Replacing the lock by another one we need to unlock it!
-      mBackLock->ReadUnlock();
+    if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
+      mBackBufferOnWhite = pool->GetTextureClient();
+      if (!mBackBufferOnWhite) {
+        mBackBuffer.Set(this, nullptr);
+        return nullptr;
+      }
     }
+
     // Create a lock for our newly created back-buffer.
     if (mManager->AsShadowForwarder()->IsSameProcess()) {
       // If our compositor is in the same process, we can save some cycles by not
       // using shared memory.
       mBackLock = new gfxMemorySharedReadLock();
     } else {
       mBackLock = new gfxShmSharedReadLock(mManager->AsShadowForwarder());
     }
@@ -1116,29 +1126,39 @@ ClientTiledLayerBuffer::ValidateTile(Til
                         &createdTextureClient, extraPainted,
                         !usingSinglePaintBuffer && !gfxPrefs::TiledDrawTargetEnabled(),
                         &backBufferOnWhite);
 
   extraPainted.MoveBy(aTileOrigin);
   extraPainted.And(extraPainted, mNewValidRegion);
   mPaintedRegion.Or(mPaintedRegion, extraPainted);
 
+  if (!backBuffer) {
+    NS_WARNING("Failed to allocate a tile TextureClient");
+    aTile.DiscardBackBuffer();
+    aTile.DiscardFrontBuffer();
+    return TileClient();
+  }
+
   // the back buffer may have been already locked in ValidateBackBufferFromFront
   if (!backBuffer->IsLocked()) {
     if (!backBuffer->Lock(OpenMode::OPEN_READ_WRITE)) {
-      NS_WARNING("Failed to lock tile TextureClient for updating.");
+      NS_WARNING("Failed to lock a tile TextureClient");
+      aTile.DiscardBackBuffer();
       aTile.DiscardFrontBuffer();
-      return aTile;
+      return TileClient();
     }
   }
+
   if (backBufferOnWhite && !backBufferOnWhite->IsLocked()) {
     if (!backBufferOnWhite->Lock(OpenMode::OPEN_READ_WRITE)) {
       NS_WARNING("Failed to lock tile TextureClient for updating.");
+      aTile.DiscardBackBuffer();
       aTile.DiscardFrontBuffer();
-      return aTile;
+      return TileClient();
     }
   }
 
   if (gfxPrefs::TiledDrawTargetEnabled()) {
     aTile.Flip();
 
     if (createdTextureClient) {
       if (!mCompositableClient->AddTextureClient(backBuffer)) {