Bug 1041744 - Don't crash if tile allocation fails. r=Bas, a=sledru
--- 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)) {