author | Matt Woodrow <mwoodrow@mozilla.com> |
Mon, 20 Oct 2014 17:04:39 +1300 | |
changeset 211362 | fa9c6845338e2e2be839d1085faf173768aaf5d6 |
parent 211360 | 223e2f4b0d47b0b739c2da4dbd7ec2e1602c58ba |
child 211363 | 3fefbf7f0b78bbde23b306d46ff405f8efec88f3 |
push id | 27674 |
push user | cbook@mozilla.com |
push date | Tue, 21 Oct 2014 13:32:11 +0000 |
treeherder | mozilla-central@313e5dcdfcb8 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | BenWa |
bugs | 1085223 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -61,60 +61,16 @@ LayerHasCheckerboardingAPZC(Layer* aLaye } return true; } break; } 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<int>(point.x), static_cast<int>(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) { if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) { // XXX - should figure out a way to render this, but for now this // is hard to do, since it will often get superimposed over the first @@ -157,22 +113,20 @@ static void PrintUniformityInfo(Layer* a LayerTranslationPayload* payload = new LayerTranslationPayload(aLayer, translation); PROFILER_MARKER_PAYLOAD("LayerTranslation", payload); #endif } /* all of the per-layer prepared data we need to maintain */ struct PreparedLayer { - PreparedLayer(LayerComposite *aLayer, RenderTargetIntRect aClipRect, bool aRestoreVisibleRegion, nsIntRegion &aVisibleRegion) : - mLayer(aLayer), mClipRect(aClipRect), mRestoreVisibleRegion(aRestoreVisibleRegion), mSavedVisibleRegion(aVisibleRegion) {} + PreparedLayer(LayerComposite *aLayer, RenderTargetIntRect aClipRect) : + mLayer(aLayer), mClipRect(aClipRect) {} LayerComposite* mLayer; RenderTargetIntRect mClipRect; - bool mRestoreVisibleRegion; - nsIntRegion mSavedVisibleRegion; }; /* all of the prepared data that we need in RenderLayer() */ struct PreparedData { RefPtr<CompositingRenderTarget> mTmpTarget; nsAutoTArray<PreparedLayer, 12> mLayers; bool mNeedsSurfaceCopy; @@ -218,48 +172,18 @@ ContainerPrepare(ContainerT* aContainer, !quad.Intersects(compositor->ClipRectInLayersCoordinates(layerToRender->GetLayer(), clipRect)) && !LayerHasCheckerboardingAPZC(layerToRender->GetLayer(), nullptr)) { CULLING_LOG("Sublayer %p is clipped entirely\n", layerToRender->GetLayer()); continue; } 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<LayerComposite*>(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<int>(-point.x), static_cast<int>(-point.y)); - CULLING_LOG(" point %i, %i\n", static_cast<int>(-point.x), static_cast<int>(-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, restoreVisibleRegion, savedVisibleRegion)); + aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender, clipRect)); } CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer()); /** * Setup our temporary surface for rendering the contents of this container. */ @@ -320,21 +244,16 @@ RenderLayers(ContainerT* aContainer, gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height); compositor->ClearRect(fbRect); layerToRender->SetClearRect(nsIntRect(0, 0, 0, 0)); } } else { 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); } if (gfxPrefs::DrawLayerInfo()) { DrawLayerInfo(clipRect, aManager, layer); }
--- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -192,16 +192,65 @@ LayerManagerComposite::BeginTransactionW } mIsCompositorReady = true; mCompositor->SetTargetContext(aTarget, aRect); mTarget = aTarget; 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) { NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); if (!mRoot) { mInTransaction = false; mIsCompositorReady = false; return false; @@ -252,16 +301,19 @@ LayerManagerComposite::EndTransaction(Dr // properties. mRoot->ApplyPendingUpdatesToSubtree(); } // The results of our drawing always go directly into a pixel buffer, // so we don't need to pass any global transform here. mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4()); + nsIntRegion opaque; + ApplyOcclusionCulling(mRoot, opaque); + Render(); mGeometryChanged = false; } else { // Modified layer tree mGeometryChanged = true; } mCompositor->ClearTargetContext();
--- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -161,16 +161,23 @@ public: virtual bool AreComponentAlphaLayersEnabled() MOZ_OVERRIDE; virtual TemporaryRef<DrawTarget> CreateOptimalMaskDrawTarget(const IntSize &aSize) MOZ_OVERRIDE; 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. */ class AutoAddMaskEffect { public: AutoAddMaskEffect(Layer* aMaskLayer, EffectChain& aEffect,
--- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -640,16 +640,36 @@ CompositorParent::ScheduleComposition() void CompositorParent::CompositeCallback() { mCurrentCompositeTask = nullptr; 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) { profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START); PROFILER_LABEL("CompositorParent", "Composite", js::ProfileEntry::Category::GRAPHICS); MOZ_ASSERT(IsInCompositorThread(), @@ -667,16 +687,17 @@ CompositorParent::CompositeToTarget(Draw mLastCompose = TimeStamp::Now(); if (!CanComposite()) { DidComposite(); return; } AutoResolveRefLayers resolve(mCompositionManager); + SetShadowProperties(mLayerManager->GetRoot()); if (aTarget) { mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect); } else { mLayerManager->BeginTransaction(); } if (mForceCompositionTask && !mOverrideComposeReadiness) { @@ -754,36 +775,16 @@ CompositorParent::ForceComposeToTarget(D bool CompositorParent::CanComposite() { return mLayerManager && mLayerManager->GetRoot() && !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) { MOZ_ASSERT(IsInCompositorThread()); if (!aIsFirstPaint && !mCompositionManager->IsFirstPaint() && @@ -821,32 +822,30 @@ CompositorParent::ShadowLayersUpdated(La AutoResolveRefLayers resolve(mCompositionManager); mApzcTreeManager->UpdatePanZoomControllerTree(this, root, aIsFirstPaint, mRootLayerTreeID, aPaintSequenceNumber); } MOZ_ASSERT(aTransactionId > mPendingTransaction); mPendingTransaction = aTransactionId; - if (root) { - SetShadowProperties(root); - } if (aScheduleComposite) { ScheduleComposition(); if (mPaused) { DidComposite(); } // When testing we synchronously update the shadow tree with the animated // values to avoid race conditions when calling GetAnimationTransform etc. // (since the above SetShadowProperties will remove animation effects). // However, we only do this update when a composite operation is already // scheduled in order to better match the behavior under regular sampling // conditions. if (mIsTesting && root && mCurrentCompositeTask) { AutoResolveRefLayers resolve(mCompositionManager); + SetShadowProperties(mLayerManager->GetRoot()); bool requestNextFrame = mCompositionManager->TransformShadowTree(mTestTime); if (!requestNextFrame) { CancelCurrentCompositeTask(); // Pretend we composited in case someone is wating for this event. DidComposite(); } } @@ -869,16 +868,17 @@ CompositorParent::SetTestSampleTime(Laye } mIsTesting = true; mTestTime = aTime; // 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(); // Pretend we composited in case someone is wating for this event. DidComposite(); } } @@ -1417,19 +1417,16 @@ CrossProcessCompositorParent::ShadowLaye const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(id); if (!state) { return; } MOZ_ASSERT(state->mParent); state->mParent->ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint); Layer* shadowRoot = aLayerTree->GetRoot(); - if (shadowRoot) { - SetShadowProperties(shadowRoot); - } UpdateIndirectTree(id, shadowRoot, aTargetConfig); state->mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite, aPaintSequenceNumber, aIsRepeatTransaction); // Send the 'remote paint ready' message to the content thread if it has already asked. if(mNotifyAfterRemotePaint) { unused << SendRemotePaintIsReady();