Bug 1176077 - Only recompute PaintedLayer item visibility when display list has changed. r=mattwoodrow

FrameLayerManager::RecomputeItemsVisibility() was being called on every
call to FrameLayerBuilder::DrawPaintedLayer(), each time for the region
to be painted by that paint call. This is inefficient when progressive
paint is enabled. Change it so that we compute the visibility of all the
layer's items within the total region to be painted, but only on the
first paint after the display list has been modified.
This commit is contained in:
Jamie Nicol 2015-07-21 09:19:25 +01:00
parent 2b55b90459
commit 5044fbd3c9
11 changed files with 49 additions and 15 deletions

View File

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

View File

@ -258,6 +258,12 @@ public:
* The callee must draw all of aRegionToDraw.
* This region is relative to 0,0 in the PaintedLayer.
*
* aDirtyRegion contains the region that is due to be painted at some point,
* even though only aRegionToDraw should be drawn during this call.
* They will often be equal, but aDirtyRegion may be larger, for example
* when painting progressively. aRegionToDraw must be entirely contained
* within aDirtyRegion.
*
* aRegionToInvalidate contains a region whose contents have been
* changed by the layer manager and which must therefore be invalidated.
* For example, this could be non-empty if a retained layer internally
@ -278,6 +284,7 @@ public:
typedef void (* DrawPaintedLayerCallback)(PaintedLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion& aDirtyRegion,
DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData);

View File

@ -734,6 +734,15 @@ RotatedContentBuffer::BorrowDrawTargetForPainting(PaintState& aPaintState,
if (!result) {
return nullptr;
}
if (result->GetBackendType() == BackendType::DIRECT2D ||
result->GetBackendType() == BackendType::DIRECT2D1_1) {
// Simplify the draw region to avoid hitting expensive drawing paths for
// complex regions. Must be applied to the entire draw region so that it
// remains a superset of the iterator's draw region.
aPaintState.mRegionToDraw.SimplifyOutwardByArea(100 * 100);
}
nsIntRegion* drawPtr = &aPaintState.mRegionToDraw;
if (aIter) {
// The iterators draw region currently only contains the bounds of the region,
@ -741,10 +750,6 @@ RotatedContentBuffer::BorrowDrawTargetForPainting(PaintState& aPaintState,
aIter->mDrawRegion.And(aIter->mDrawRegion, aPaintState.mRegionToDraw);
drawPtr = &aIter->mDrawRegion;
}
if (result->GetBackendType() == BackendType::DIRECT2D ||
result->GetBackendType() == BackendType::DIRECT2D1_1) {
drawPtr->SimplifyOutwardByArea(100 * 100);
}
if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
if (!mDTBuffer || !mDTBufferOnWhite) {

View File

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

View File

@ -112,8 +112,8 @@ protected:
BasicManager()->SetTransactionIncomplete();
return;
}
aCallback(this, aContext, aExtendedRegionToDraw, aClip,
aRegionToInvalidate, aCallbackData);
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
// here (OR doesn't automatically simplify to the simplest possible

View File

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

View File

@ -311,7 +311,8 @@ ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion,
TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this, Stringify(mValidRegion).c_str());
mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution);
mContentClient->mTiledBuffer.PaintThebes(mValidRegion, aInvalidRegion, aCallback, aCallbackData);
mContentClient->mTiledBuffer.PaintThebes(mValidRegion, aInvalidRegion, aInvalidRegion,
aCallback, aCallbackData);
mPaintData.mPaintFinished = true;
return true;
}

View File

@ -877,6 +877,7 @@ ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
void
ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData)
{
@ -929,7 +930,8 @@ ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw",
js::ProfileEntry::Category::GRAPHICS);
mCallback(mPaintedLayer, ctxt, aPaintRegion, DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
mCallback(mPaintedLayer, ctxt, aPaintRegion, aDirtyRegion,
DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
}
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
@ -1063,7 +1065,8 @@ ClientTiledLayerBuffer::PostValidate(const nsIntRegion& aPaintRegion)
ctx->SetMatrix(
ctx->CurrentMatrix().Scale(mResolution, mResolution).Translate(ThebesPoint(-mTilingOrigin)));
mCallback(mPaintedLayer, ctx, aPaintRegion, DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
mCallback(mPaintedLayer, ctx, aPaintRegion, aPaintRegion,
DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
mMoz2DTiles.clear();
// Reset:
mTilingOrigin = IntPoint(std::numeric_limits<int32_t>::max(),
@ -1640,7 +1643,8 @@ ClientTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
validOrStale.Or(aValidRegion, aOldValidRegion);
// Paint the computed region and subtract it from the invalid region.
PaintThebes(validOrStale, regionToPaint, aCallback, aCallbackData);
PaintThebes(validOrStale, regionToPaint, aInvalidRegion,
aCallback, aCallbackData);
aInvalidRegion.Sub(aInvalidRegion, regionToPaint);
} while (repeat);

View File

@ -415,6 +415,7 @@ public:
void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData);

View File

@ -1367,7 +1367,8 @@ public:
mXScale(1.f), mYScale(1.f),
mAppUnitsPerDevPixel(0),
mTranslation(0, 0),
mAnimatedGeometryRootPosition(0, 0) {}
mAnimatedGeometryRootPosition(0, 0),
mNeedsRecomputeVisibility(false) {}
/**
* Record the number of clips in the PaintedLayer's mask layer.
@ -1438,6 +1439,11 @@ 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;
};
/*
@ -2275,6 +2281,8 @@ ContainerState::PreparePaintedLayerForUse(PaintedLayer* aLayer,
ComputeAndSetIgnoreInvalidationRect(aLayer, aData, aAnimatedGeometryRoot, mBuilder, pixOffset);
aData->mNeedsRecomputeVisibility = true;
// FIXME: Temporary workaround for bug 681192 and bug 724786.
#ifndef MOZ_WIDGET_ANDROID
// Calculate exact position of the top-left of the active scrolled root.
@ -5535,6 +5543,7 @@ private:
FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion& aDirtyRegion,
DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData)
@ -5587,14 +5596,16 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
nsIntPoint offset = GetTranslationForPaintedLayer(aLayer);
nsPresContext* presContext = entry->mContainerLayerFrame->PresContext();
if (!layerBuilder->GetContainingPaintedLayerData()) {
if (userData->mNeedsRecomputeVisibility &&
!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.
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
RecomputeVisibilityForItems(entry->mItems, builder, aRegionToDraw,
RecomputeVisibilityForItems(entry->mItems, builder, aDirtyRegion,
offset, appUnitsPerDevPixel,
userData->mXScale, userData->mYScale);
userData->mNeedsRecomputeVisibility = false;
}
nsRenderingContext rc(aContext);

View File

@ -281,11 +281,13 @@ public:
* This callback must be provided to EndTransaction. The callback data
* must be the nsDisplayListBuilder containing this FrameLayerBuilder.
* This function can be called multiple times in a row to draw
* different regions.
* different regions. This will occur when, for example, progressive paint is
* enabled, in which case aRegionToDraw will be a subregion of aDirtyRegion.
*/
static void DrawPaintedLayer(PaintedLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion& aDirtyRegion,
mozilla::layers::DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData);