Bug 629866. Part 2: Make MarkLeafLayersHidden actually hide layers that aren't in the dirty region. Don't consider hidden layers when deciding whether double-buffering is needed. r=cjones

This commit is contained in:
Robert O'Callahan 2011-05-17 11:41:39 +12:00
parent fa4e75ab4d
commit 0bca45c661
2 changed files with 88 additions and 44 deletions

View File

@ -92,7 +92,7 @@ class ShadowableLayer;
*/
class BasicImplData {
public:
BasicImplData()
BasicImplData() : mHidden(PR_FALSE)
{
MOZ_COUNT_CTOR(BasicImplData);
}
@ -136,16 +136,13 @@ public:
virtual void ClearCachedResources() {}
/**
* This variable is used by layer manager in order to
* MarkLeafLayersCoveredByOpaque() before painting.
* We keep it here for now. Once we need to cull completely covered
* non-Basic layers, mCoveredByOpaque should be moved to Layer.
* This variable is set by MarkLeafLayersHidden() before painting.
*/
void SetCoveredByOpaque(PRBool aCovered) { mCoveredByOpaque = aCovered; }
PRBool IsCoveredByOpaque() const { return mCoveredByOpaque; }
void SetHidden(PRBool aCovered) { mHidden = aCovered; }
PRBool IsHidden() const { return PR_FALSE; }
protected:
PRPackedBool mCoveredByOpaque;
PRPackedBool mHidden;
};
static BasicImplData*
@ -554,7 +551,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
mBuffer.Clear();
nsIntRegion toDraw = IntersectWithClip(mVisibleRegion, aContext);
if (!toDraw.IsEmpty()) {
if (!toDraw.IsEmpty() && !IsHidden()) {
if (!aCallback) {
BasicManager()->SetTransactionIncomplete();
return;
@ -620,7 +617,9 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
}
}
mBuffer.DrawTo(this, aContext, opacity);
if (!IsHidden()) {
mBuffer.DrawTo(this, aContext, opacity);
}
for (PRUint32 i = 0; i < readbackUpdates.Length(); ++i) {
ReadbackProcessor::Update& update = readbackUpdates[i];
@ -739,6 +738,8 @@ protected:
void
BasicImageLayer::Paint(gfxContext* aContext)
{
if (IsHidden())
return;
nsRefPtr<gfxPattern> dontcare =
GetAndPaintCurrentImage(aContext, GetEffectiveOpacity());
}
@ -850,6 +851,8 @@ public:
virtual void Paint(gfxContext* aContext)
{
if (IsHidden())
return;
PaintColorTo(mColor, GetEffectiveOpacity(), aContext);
}
@ -994,6 +997,8 @@ BasicCanvasLayer::UpdateSurface()
void
BasicCanvasLayer::Paint(gfxContext* aContext)
{
if (IsHidden())
return;
UpdateSurface();
FireDidTransactionCallback();
PaintWithOpacity(aContext, GetEffectiveOpacity());
@ -1084,6 +1089,11 @@ MayHaveOverlappingOrTransparentLayers(Layer* aLayer,
const nsIntRect& aBounds,
nsIntRegion* aDirtyVisibleRegionInContainer)
{
if (static_cast<BasicImplData*>(aLayer->ImplData())->IsHidden()) {
// This layer won't be painted, so just ignore it.
return PR_FALSE;
}
if (!(aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE)) {
return PR_TRUE;
}
@ -1244,17 +1254,27 @@ TransformIntRect(nsIntRect& aRect, const gfxMatrix& aMatrix,
aRect = (*aRoundMethod)(gr);
}
// This implementation assumes that GetEffectiveTransform transforms
// all layers to the same coordinate system. It can't be used as is
// by accelerated layers because of intermediate surfaces.
// aClipRect and aRegion are in that global coordinate system.
/**
* This function assumes that GetEffectiveTransform transforms
* all layers to the same coordinate system (the "root coordinate system").
* It can't be used as is by accelerated layers because of intermediate surfaces.
* This must set the hidden flag to true or false on *all* layers in the subtree.
* @param aClipRect the cliprect, in the root coordinate system. We assume
* that any layer drawing is clipped to this rect. It is therefore not
* allowed to add to the opaque region outside that rect.
* @param aDirtyRect the dirty rect that will be painted, in the root
* coordinate system. Layers outside this rect should be hidden.
* @param aOpaqueRegion the opaque region covering aLayer, in the
* root coordinate system.
*/
static void
MarkLeafLayersCoveredByOpaque(Layer* aLayer, const nsIntRect& aClipRect,
nsIntRegion& aRegion)
MarkLeafLayersHidden(Layer* aLayer, const nsIntRect& aClipRect,
const nsIntRect& aDirtyRect,
nsIntRegion& aOpaqueRegion)
{
Layer* child = aLayer->GetLastChild();
BasicImplData* data = ToData(aLayer);
data->SetCoveredByOpaque(PR_FALSE);
data->SetHidden(PR_FALSE);
nsIntRect newClipRect(aClipRect);
@ -1274,6 +1294,8 @@ MarkLeafLayersCoveredByOpaque(Layer* aLayer, const nsIntRect& aClipRect,
if (aLayer->GetParent()) {
gfxMatrix tr;
if (aLayer->GetParent()->GetEffectiveTransform().Is2D(&tr)) {
// Clip rect is applied after aLayer's transform, i.e., in the coordinate
// system of aLayer's parent.
TransformIntRect(cr, tr, ToInsideIntRect);
} else {
cr.SetRect(0, 0, 0, 0);
@ -1292,7 +1314,8 @@ MarkLeafLayersCoveredByOpaque(Layer* aLayer, const nsIntRect& aClipRect,
nsIntRegion region = aLayer->GetEffectiveVisibleRegion();
nsIntRect r = region.GetBounds();
TransformIntRect(r, transform, ToOutsideIntRect);
data->SetCoveredByOpaque(aRegion.Contains(r));
r.IntersectRect(r, aDirtyRect);
data->SetHidden(aOpaqueRegion.Contains(r));
// Allow aLayer to cover underlying layers only if aLayer's
// content is opaque
@ -1307,12 +1330,12 @@ MarkLeafLayersCoveredByOpaque(Layer* aLayer, const nsIntRect& aClipRect,
r.IntersectRect(r, newClipRect);
if (!r.IsEmpty()) {
aRegion.Or(aRegion, r);
aOpaqueRegion.Or(aOpaqueRegion, r);
}
}
} else {
for (; child; child = child->GetPrevSibling()) {
MarkLeafLayersCoveredByOpaque(child, newClipRect, aRegion);
MarkLeafLayersHidden(child, newClipRect, aDirtyRect, aOpaqueRegion);
}
}
}
@ -1341,29 +1364,48 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
mTransactionIncomplete = false;
if (mTarget && mRoot) {
nsRefPtr<gfxContext> finalTarget = mTarget;
gfxPoint cachedSurfaceOffset;
nsIntRegion rootRegion;
PRBool useDoubleBuffering = mUsingDefaultTarget &&
mDoubleBuffering != BUFFER_NONE &&
MayHaveOverlappingOrTransparentLayers(mRoot,
ToOutsideIntRect(mTarget->GetClipExtents()),
&rootRegion);
if (useDoubleBuffering) {
nsRefPtr<gfxASurface> targetSurface = mTarget->CurrentSurface();
mTarget = PushGroupWithCachedSurface(mTarget, targetSurface->GetContentType(),
&cachedSurfaceOffset);
nsIntRect clipRect;
if (HasShadowManager()) {
// If this has a shadow manager, the clip extents of mTarget are meaningless.
// So instead just use the root layer's visible region bounds.
const nsIntRect& bounds = mRoot->GetVisibleRegion().GetBounds();
gfxRect deviceRect =
mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
clipRect = ToOutsideIntRect(deviceRect);
} else {
gfxContextMatrixAutoSaveRestore save(mTarget);
mTarget->SetMatrix(gfxMatrix());
clipRect = ToOutsideIntRect(mTarget->GetClipExtents());
}
// Need to do this before we call MarkLeafLayersHidden,
// which depends on correct effective transforms
mSnapEffectiveTransforms =
!(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING);
mRoot->ComputeEffectiveTransforms(gfx3DMatrix::From2D(mTarget->CurrentMatrix()));
nsIntRegion region;
MarkLeafLayersCoveredByOpaque(mRoot,
mRoot->GetEffectiveVisibleRegion().GetBounds(),
region);
// Need to do this before we call MayHaveOverlappingOrTransparentLayers,
// which uses information about which layers are going to be drawn.
if (IsRetained()) {
nsIntRegion region;
MarkLeafLayersHidden(mRoot, clipRect, clipRect, region);
}
nsRefPtr<gfxContext> finalTarget = mTarget;
gfxPoint cachedSurfaceOffset;
nsIntRegion rootRegion;
PRBool useDoubleBuffering = mUsingDefaultTarget &&
mDoubleBuffering != BUFFER_NONE &&
MayHaveOverlappingOrTransparentLayers(mRoot, clipRect, &rootRegion);
if (useDoubleBuffering) {
nsRefPtr<gfxASurface> targetSurface = mTarget->CurrentSurface();
mTarget = PushGroupWithCachedSurface(mTarget, targetSurface->GetContentType(),
&cachedSurfaceOffset);
// Recompute effective transforms since the gfxContext matrix has changed
mRoot->ComputeEffectiveTransforms(gfx3DMatrix::From2D(mTarget->CurrentMatrix()));
}
PaintLayer(mRoot, aCallback, aCallbackData, nsnull);
// If we're doing manual double-buffering, we need to avoid drawing
@ -1495,14 +1537,12 @@ BasicLayerManager::PaintLayer(Layer* aLayer,
BasicImplData* data = ToData(aLayer);
#ifdef MOZ_LAYERS_HAVE_LOG
MOZ_LAYERS_LOG(("%s (0x%p) is covered: %i\n", __FUNCTION__,
(void*)aLayer, data->IsCoveredByOpaque()));
(void*)aLayer, data->IsHidden()));
#endif
if (!data->IsCoveredByOpaque()) {
if (aLayer->AsThebesLayer()) {
data->PaintThebes(mTarget, aCallback, aCallbackData, aReadback);
} else {
data->Paint(mTarget);
}
if (aLayer->AsThebesLayer()) {
data->PaintThebes(mTarget, aCallback, aCallbackData, aReadback);
} else {
data->Paint(mTarget);
}
} else {
ReadbackProcessor readback;

View File

@ -181,6 +181,8 @@ public:
void SetTransactionIncomplete() { mTransactionIncomplete = true; }
virtual PRBool IsCompositingCheap() { return PR_FALSE; }
virtual bool HasShadowManagerInternal() const { return false; }
bool HasShadowManager() const { return HasShadowManagerInternal(); }
protected:
#ifdef DEBUG
@ -260,6 +262,7 @@ public:
ShadowableLayer* Hold(Layer* aLayer);
bool HasShadowManager() const { return ShadowLayerForwarder::HasShadowManager(); }
PLayersChild* GetShadowManager() const { return mShadowManager; }
void SetShadowManager(PLayersChild* aShadowManager)
@ -268,6 +271,7 @@ public:
}
virtual PRBool IsCompositingCheap();
virtual bool HasShadowManagerInternal() const { return HasShadowManager(); }
private:
/**