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 216730 9148cd599e9f
parent 216729 c21b3ccb9c19
child 216731 ff9cef7b2f9d
push id3892
push userryanvm@gmail.com
push date2014-09-15 14:56 +0000
treeherdermozilla-beta@cd04e5bf0fec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, sledru
bugs1041744
milestone33.0
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
@@ -597,28 +597,33 @@ TileClient::GetBackBuffer(const nsIntReg
     // re-use the front buffer.
     DiscardBackBuffer();
     Flip();
     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.
       aPool->ReportClientLost();
     }
     mBackBuffer = aPool->GetTextureClient();
+    if (!mBackBuffer) {
+      return nullptr;
+    }
 
-    if (mBackLock) {
-      // Before we Replacing the lock by another one we need to unlock it!
-      mBackLock->ReadUnlock();
-    }
     // 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());
     }
@@ -851,20 +856,28 @@ ClientTiledLayerBuffer::ValidateTile(Til
   offsetScaledDirtyRegion.ScaleRoundOut(mResolution, mResolution);
 
   bool usingSinglePaintBuffer = !!mSinglePaintDrawTarget;
   RefPtr<TextureClient> backBuffer =
     aTile.GetBackBuffer(offsetScaledDirtyRegion,
                         mManager->GetTexturePool(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType())),
                         &createdTextureClient, !usingSinglePaintBuffer);
 
+  if (!backBuffer) {
+    NS_WARNING("Failed to allocate a tile TextureClient");
+    aTile.DiscardBackBuffer();
+    aTile.DiscardFrontBuffer();
+    return TileClient();
+  }
+
   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();
   }
 
   // We must not keep a reference to the DrawTarget after it has been unlocked,
   // make sure these are null'd before unlocking as destruction of the context
   // may cause the target to be flushed.
   RefPtr<DrawTarget> drawTarget = backBuffer->BorrowDrawTarget();
   drawTarget->SetTransform(Matrix());