Bug 1200729 - Recompute FrameLayerBuilder item visibility if dirty region changes. r=mwoodrow

Make the FrameLayerBuilder remember for what region it has calculated
display item visibility, then recompute the visibility whenever the
dirty region it is passed to DrawPaintedLayer changes.

This means that the caller does not have to know the entire dirty region
that will be drawn for the transaction, but we can still optimise cases
where it knows some of the dirty region in advance.

This fixes a regression where MultiTiledContentClient's low-res display
port would not be painted if a smaller region of its high-res buffer had
already been painted that transaction, since the FrameLayerBuilder
had decided that most of the larger low-res region was invisible.
This commit is contained in:
Jamie Nicol 2015-09-15 14:41:42 +01:00
parent 0853ab2eac
commit 709cbe92db
9 changed files with 35 additions and 36 deletions

View File

@ -1688,7 +1688,7 @@ static void
DrawPaintedLayer(PaintedLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion* aDirtyRegion,
const nsIntRegion& aDirtyRegion,
DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData)

View File

@ -259,11 +259,12 @@ public:
* The callee must draw all of aRegionToDraw.
* This region is relative to 0,0 in the PaintedLayer.
*
* aDirtyRegion, if non-null, contains the total region that is due to be
* painted during the transaction, even though only aRegionToDraw should
* be drawn during this call. The sum of every aRegionToDraw over the
* course of the transaction must equal aDirtyRegion. aDirtyRegion can be
* null if the total dirty region is unknown.
* aDirtyRegion should contain the total region that is be due to be painted
* during the transaction, even though only aRegionToDraw should be drawn
* during this call. aRegionToDraw must be entirely contained within
* aDirtyRegion. If the total dirty region is unknown it is okay to pass a
* subregion of the total dirty region, e.g. just aRegionToDraw, though it
* may not be as efficient.
*
* aRegionToInvalidate contains a region whose contents have been
* changed by the layer manager and which must therefore be invalidated.
@ -285,7 +286,7 @@ public:
typedef void (* DrawPaintedLayerCallback)(PaintedLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion* aDirtyRegion,
const nsIntRegion& aDirtyRegion,
DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData);

View File

@ -91,7 +91,7 @@ BasicPaintedLayer::PaintThebes(gfxContext* aContext,
groupContext = aContext;
}
SetAntialiasingFlags(this, groupContext->GetDrawTarget());
aCallback(this, groupContext, toDraw, &toDraw,
aCallback(this, groupContext, toDraw, toDraw,
DrawRegionClip::NONE, nsIntRegion(), aCallbackData);
if (needsGroup) {
aContext->PopGroupToSource();

View File

@ -112,7 +112,7 @@ protected:
BasicManager()->SetTransactionIncomplete();
return;
}
aCallback(this, aContext, aExtendedRegionToDraw, &aExtendedRegionToDraw,
aCallback(this, aContext, aExtendedRegionToDraw, aExtendedRegionToDraw,
aClip, aRegionToInvalidate, aCallbackData);
// Everything that's visible has been validated. Do this instead of just
// OR-ing with aRegionToDraw, since that can lead to a very complex region

View File

@ -87,7 +87,7 @@ ClientPaintedLayer::PaintThebes()
ClientManager()->GetPaintedLayerCallback()(this,
ctx,
iter.mDrawRegion,
nullptr,
iter.mDrawRegion,
state.mClip,
state.mRegionToInvalidate,
ClientManager()->GetPaintedLayerCallbackData());

View File

@ -181,7 +181,7 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
nsRefPtr<gfxContext> ctx = new gfxContext(dt);
ctx->SetMatrix(ctx->CurrentMatrix().Translate(-mTilingOrigin.x, -mTilingOrigin.y));
aCallback(mPaintedLayer, ctx, paintRegion, &paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
aCallback(mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
}
// Mark the area we just drew into the back buffer as invalid in the front buffer as they're

View File

@ -964,7 +964,7 @@ ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
PROFILER_LABEL("ClientMultiTiledLayerBuffer", "PaintThebesSingleBufferDraw",
js::ProfileEntry::Category::GRAPHICS);
mCallback(mPaintedLayer, ctxt, aPaintRegion, &aDirtyRegion,
mCallback(mPaintedLayer, ctxt, aPaintRegion, aDirtyRegion,
DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
}
@ -1171,7 +1171,7 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
ctx->SetMatrix(
ctx->CurrentMatrix().Scale(mResolution, mResolution).Translate(ThebesPoint(-mTilingOrigin)));
mCallback(mPaintedLayer, ctx, aPaintRegion, &aDirtyRegion,
mCallback(mPaintedLayer, ctx, aPaintRegion, aDirtyRegion,
DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
mMoz2DTiles.clear();
// Reset:

View File

@ -1420,8 +1420,7 @@ public:
mXScale(1.f), mYScale(1.f),
mAppUnitsPerDevPixel(0),
mTranslation(0, 0),
mAnimatedGeometryRootPosition(0, 0),
mNeedsRecomputeVisibility(false) {}
mAnimatedGeometryRootPosition(0, 0) {}
/**
* Record the number of clips in the PaintedLayer's mask layer.
@ -1493,10 +1492,12 @@ public:
nsRefPtr<ColorLayer> mColorLayer;
nsRefPtr<ImageLayer> mImageLayer;
// True if the display items for this layer have changed and we need a call
// to RecomputeVisibilityForItems before painting them. This can be false
// during the latter iterations of progressive painting.
bool mNeedsRecomputeVisibility;
// The region for which display item visibility for this layer has already
// been calculated. Used to reduce the number of calls to
// RecomputeVisibilityForItems if it is known in advance that a larger
// region will be painted during a transaction than in a single call to
// DrawPaintedLayer, for example when progressive paint is enabled.
nsIntRegion mVisibilityComputedRegion;
};
/*
@ -2339,7 +2340,7 @@ ContainerState::PreparePaintedLayerForUse(PaintedLayer* aLayer,
ComputeAndSetIgnoreInvalidationRect(aLayer, aData, aAnimatedGeometryRoot, mBuilder, pixOffset);
aData->mNeedsRecomputeVisibility = true;
aData->mVisibilityComputedRegion.SetEmpty();
// FIXME: Temporary workaround for bug 681192 and bug 724786.
#ifndef MOZ_WIDGET_ANDROID
@ -5716,7 +5717,7 @@ static void DrawForcedBackgroundColor(DrawTarget& aDrawTarget,
FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion* aDirtyRegion,
const nsIntRegion& aDirtyRegion,
DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData)
@ -5769,21 +5770,18 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
nsIntPoint offset = GetTranslationForPaintedLayer(aLayer);
nsPresContext* presContext = entry->mContainerLayerFrame->PresContext();
if (userData->mNeedsRecomputeVisibility &&
if (!userData->mVisibilityComputedRegion.Contains(aDirtyRegion) &&
!layerBuilder->GetContainingPaintedLayerData()) {
// Recompute visibility of items in our PaintedLayer. Note that this
// recomputes visibility for all descendants of our display items too,
// so there's no need to do this for the items in inactive PaintedLayers.
// If aDirtyRegion is non-null then recompute the visibility of the entire
// aDirtyRegion at once, rather of aRegionToDraw separately on each call.
// Recompute visibility of items in our PaintedLayer, if required. Note
// that this recomputes visibility for all descendants of our display
// items too, so there's no need to do this for the items in inactive
// PaintedLayers. If aDirtyRegion has not changed since the previous call
// then we can skip this.
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
RecomputeVisibilityForItems(entry->mItems, builder,
aDirtyRegion ? *aDirtyRegion : aRegionToDraw,
RecomputeVisibilityForItems(entry->mItems, builder, aDirtyRegion,
offset, appUnitsPerDevPixel,
userData->mXScale, userData->mYScale);
if (aDirtyRegion) {
userData->mNeedsRecomputeVisibility = false;
}
userData->mVisibilityComputedRegion = aDirtyRegion;
}
nsRenderingContext rc(aContext);

View File

@ -282,14 +282,14 @@ public:
* must be the nsDisplayListBuilder containing this FrameLayerBuilder.
* This function can be called multiple times in a row to draw
* different regions. This will occur when, for example, progressive paint is
* enabled. In these cases aDirtyRegion can optionally be used to specify the
* total region that will be drawn during the transaction, possibly allowing
* the callback to make optimizations.
* enabled. In these cases aDirtyRegion can be used to specify a larger region
* than aRegionToDraw that will be drawn during the transaction, possibly
* allowing the callback to make optimizations.
*/
static void DrawPaintedLayer(PaintedLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion* aDirtyRegion,
const nsIntRegion& aDirtyRegion,
mozilla::layers::DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData);