diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index b854831be57f..68c339de04aa 100644 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -66,6 +66,50 @@ LayerHasCheckerboardingAPZC(Layer* aLayer, gfxRGBA* aOutColor) return false; } +/** + * Returns a rectangle of content painted opaquely by aLayer. Very consertative; + * bails by returning an empty rect in any tricky situations. + */ +static nsIntRect +GetOpaqueRect(Layer* aLayer) +{ + nsIntRect result; + gfx::Matrix matrix; + bool is2D = aLayer->AsLayerComposite()->GetShadowTransform().Is2D(&matrix); + + // Just bail if there's anything difficult to handle. + if (!is2D || aLayer->GetMaskLayer() || + aLayer->GetIsFixedPosition() || + aLayer->GetIsStickyPosition() || + aLayer->GetEffectiveOpacity() != 1.0f || + matrix.HasNonIntegerTranslation()) { + return result; + } + + if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) { + result = aLayer->GetEffectiveVisibleRegion().GetLargestRectangle(); + } else { + // Drill down into RefLayers because that's what we particularly care about; + // layer construction for aLayer will not have known about the opaqueness + // of any RefLayer subtrees. + RefLayer* refLayer = aLayer->AsRefLayer(); + if (refLayer && refLayer->GetFirstChild()) { + result = GetOpaqueRect(refLayer->GetFirstChild()); + } + } + + // Translate our opaque region to cover the child + gfx::Point point = matrix.GetTranslation(); + result.MoveBy(static_cast(point.x), static_cast(point.y)); + + const nsIntRect* clipRect = aLayer->GetEffectiveClipRect(); + if (clipRect) { + result.IntersectRect(result, *clipRect); + } + + return result; +} + static void DrawLayerInfo(const RenderTargetIntRect& aClipRect, LayerManagerComposite* aManager, Layer* aLayer) @@ -118,10 +162,12 @@ static void PrintUniformityInfo(Layer* aLayer) /* all of the per-layer prepared data we need to maintain */ struct PreparedLayer { - PreparedLayer(LayerComposite *aLayer, RenderTargetIntRect aClipRect) : - mLayer(aLayer), mClipRect(aClipRect) {} + PreparedLayer(LayerComposite *aLayer, RenderTargetIntRect aClipRect, bool aRestoreVisibleRegion, nsIntRegion &aVisibleRegion) : + mLayer(aLayer), mClipRect(aClipRect), mRestoreVisibleRegion(aRestoreVisibleRegion), mSavedVisibleRegion(aVisibleRegion) {} LayerComposite* mLayer; RenderTargetIntRect mClipRect; + bool mRestoreVisibleRegion; + nsIntRegion mSavedVisibleRegion; }; /* all of the prepared data that we need in RenderLayer() */ @@ -177,8 +223,38 @@ ContainerPrepare(ContainerT* aContainer, CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer()); + nsIntRegion savedVisibleRegion; + bool restoreVisibleRegion = false; + gfx::Matrix matrix; + bool is2D = layerToRender->GetLayer()->GetBaseTransform().Is2D(&matrix); + if (i + 1 < children.Length() && + is2D && !matrix.HasNonIntegerTranslation()) { + LayerComposite* nextLayer = static_cast(children.ElementAt(i + 1)->ImplData()); + CULLING_LOG("Culling against %p\n", nextLayer->GetLayer()); + nsIntRect nextLayerOpaqueRect; + if (nextLayer && nextLayer->GetLayer()) { + nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer()); + gfx::Point point = matrix.GetTranslation(); + nextLayerOpaqueRect.MoveBy(static_cast(-point.x), static_cast(-point.y)); + CULLING_LOG(" point %i, %i\n", static_cast(-point.x), static_cast(-point.y)); + CULLING_LOG(" opaque rect %i, %i, %i, %i\n", nextLayerOpaqueRect.x, nextLayerOpaqueRect.y, nextLayerOpaqueRect.width, nextLayerOpaqueRect.height); + } + if (!nextLayerOpaqueRect.IsEmpty()) { + CULLING_LOG(" draw\n"); + savedVisibleRegion = layerToRender->GetShadowVisibleRegion(); + nsIntRegion visibleRegion; + visibleRegion.Sub(savedVisibleRegion, nextLayerOpaqueRect); + if (visibleRegion.IsEmpty()) { + continue; + } + layerToRender->SetShadowVisibleRegion(visibleRegion); + restoreVisibleRegion = true; + } else { + CULLING_LOG(" skip\n"); + } + } layerToRender->Prepare(clipRect); - aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender, clipRect)); + aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender, clipRect, restoreVisibleRegion, savedVisibleRegion)); } CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer()); @@ -249,6 +325,11 @@ RenderLayers(ContainerT* aContainer, layerToRender->RenderLayer(RenderTargetPixel::ToUntyped(clipRect)); } + if (preparedData.mRestoreVisibleRegion) { + // Restore the region in case it's not covered by opaque content next time + layerToRender->SetShadowVisibleRegion(preparedData.mSavedVisibleRegion); + } + if (gfxPrefs::UniformityInfo()) { PrintUniformityInfo(layer); } diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index da6aada14efe..e57651d17c84 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -197,55 +197,6 @@ LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget, const mTargetBounds = aRect; } -void -LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion) -{ - nsIntRegion localOpaque; - Matrix transform2d; - bool isTranslation = false; - // If aLayer has a simple transform (only an integer translation) then we - // can easily convert aOpaqueRegion into pre-transform coordinates and include - // that region. - if (aLayer->GetLocalTransform().Is2D(&transform2d)) { - if (transform2d.IsIntegerTranslation()) { - isTranslation = true; - localOpaque = aOpaqueRegion; - localOpaque.MoveBy(-transform2d._31, -transform2d._32); - } - } - - // Subtract any areas that we know to be opaque from our - // visible region. - LayerComposite *composite = aLayer->AsLayerComposite(); - if (!localOpaque.IsEmpty()) { - nsIntRegion visible = composite->GetShadowVisibleRegion(); - visible.Sub(visible, localOpaque); - composite->SetShadowVisibleRegion(visible); - } - - // Compute occlusions for our descendants (in front-to-back order) and allow them to - // contribute to localOpaque. - for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) { - ApplyOcclusionCulling(child, localOpaque); - } - - // If we have a simple transform, then we can add our opaque area into - // aOpaqueRegion. - if (isTranslation && - !aLayer->GetMaskLayer() && - aLayer->GetLocalOpacity() == 1.0f) { - if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) { - localOpaque.Or(localOpaque, composite->GetShadowVisibleRegion()); - } - localOpaque.MoveBy(transform2d._31, transform2d._32); - const nsIntRect* clip = aLayer->GetEffectiveClipRect(); - if (clip) { - localOpaque.And(localOpaque, *clip); - } - aOpaqueRegion.Or(aOpaqueRegion, localOpaque); - } -} - bool LayerManagerComposite::EndEmptyTransaction(EndTransactionFlags aFlags) { @@ -306,9 +257,6 @@ LayerManagerComposite::EndTransaction(DrawPaintedLayerCallback aCallback, // so we don't need to pass any global transform here. mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4()); - nsIntRegion opaque; - ApplyOcclusionCulling(mRoot, opaque); - Render(); mGeometryChanged = false; } else { diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h index d195aabb95fe..86345cd5365b 100644 --- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -165,13 +165,6 @@ public: virtual const char* Name() const MOZ_OVERRIDE { return ""; } - /** - * Restricts the shadow visible region of layers that are covered with - * opaque content. aOpaqueRegion is the region already known to be covered - * with opaque content, in the post-transform coordinate space of aLayer. - */ - void ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion); - /** * RAII helper class to add a mask effect with the compositable from aMaskLayer * to the EffectChain aEffect and notify the compositable when we are done. diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 41ece1f22a4c..e04dc502935d 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -645,26 +645,6 @@ CompositorParent::CompositeCallback() CompositeToTarget(nullptr); } -// Go down the composite layer tree, setting properties to match their -// content-side counterparts. -static void -SetShadowProperties(Layer* aLayer) -{ - // FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate. - LayerComposite* layerComposite = aLayer->AsLayerComposite(); - // Set the layerComposite's base transform to the layer's base transform. - layerComposite->SetShadowTransform(aLayer->GetBaseTransform()); - layerComposite->SetShadowTransformSetByAnimation(false); - layerComposite->SetShadowVisibleRegion(aLayer->GetVisibleRegion()); - layerComposite->SetShadowClipRect(aLayer->GetClipRect()); - layerComposite->SetShadowOpacity(aLayer->GetOpacity()); - - for (Layer* child = aLayer->GetFirstChild(); - child; child = child->GetNextSibling()) { - SetShadowProperties(child); - } -} - void CompositorParent::CompositeToTarget(DrawTarget* aTarget, const nsIntRect* aRect) { @@ -692,7 +672,6 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const nsIntRect* aRect) } AutoResolveRefLayers resolve(mCompositionManager); - SetShadowProperties(mLayerManager->GetRoot()); if (aTarget) { mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect); @@ -780,6 +759,26 @@ CompositorParent::CanComposite() !mPaused; } +// Go down the composite layer tree, setting properties to match their +// content-side counterparts. +static void +SetShadowProperties(Layer* aLayer) +{ + // FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate. + LayerComposite* layerComposite = aLayer->AsLayerComposite(); + // Set the layerComposite's base transform to the layer's base transform. + layerComposite->SetShadowTransform(aLayer->GetBaseTransform()); + layerComposite->SetShadowTransformSetByAnimation(false); + layerComposite->SetShadowVisibleRegion(aLayer->GetVisibleRegion()); + layerComposite->SetShadowClipRect(aLayer->GetClipRect()); + layerComposite->SetShadowOpacity(aLayer->GetOpacity()); + + for (Layer* child = aLayer->GetFirstChild(); + child; child = child->GetNextSibling()) { + SetShadowProperties(child); + } +} + void CompositorParent::ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig, bool aIsFirstPaint) @@ -827,6 +826,9 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, MOZ_ASSERT(aTransactionId > mPendingTransaction); mPendingTransaction = aTransactionId; + if (root) { + SetShadowProperties(root); + } if (aScheduleComposite) { ScheduleComposition(); if (mPaused) { @@ -840,7 +842,6 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, // conditions. if (mIsTesting && root && mCurrentCompositeTask) { AutoResolveRefLayers resolve(mCompositionManager); - SetShadowProperties(mLayerManager->GetRoot()); bool requestNextFrame = mCompositionManager->TransformShadowTree(mTestTime); if (!requestNextFrame) { @@ -873,7 +874,6 @@ CompositorParent::SetTestSampleTime(LayerTransactionParent* aLayerTree, // Update but only if we were already scheduled to animate if (mCompositionManager && mCurrentCompositeTask) { AutoResolveRefLayers resolve(mCompositionManager); - SetShadowProperties(mLayerManager->GetRoot()); bool requestNextFrame = mCompositionManager->TransformShadowTree(aTime); if (!requestNextFrame) { CancelCurrentCompositeTask(); @@ -1436,6 +1436,9 @@ CrossProcessCompositorParent::ShadowLayersUpdated( state->mParent->ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint); Layer* shadowRoot = aLayerTree->GetRoot(); + if (shadowRoot) { + SetShadowProperties(shadowRoot); + } UpdateIndirectTree(id, shadowRoot, aTargetConfig); state->mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite,