From c8d82e8dcdd0fd57cdcf7bed1162a6d381676c69 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Tue, 15 Oct 2013 16:23:21 +1300 Subject: [PATCH] Bug 922942 - Add a Validate() pass to BasicLayers to avoid needing to create a dummy destination context. r=roc --- gfx/layers/basic/BasicContainerLayer.cpp | 14 +++ gfx/layers/basic/BasicContainerLayer.h | 3 + gfx/layers/basic/BasicImplData.h | 3 + gfx/layers/basic/BasicLayerManager.cpp | 62 +++++------- gfx/layers/basic/BasicLayers.h | 1 - gfx/layers/basic/BasicThebesLayer.cpp | 124 ++++++++++++----------- gfx/layers/basic/BasicThebesLayer.h | 3 + 7 files changed, 114 insertions(+), 96 deletions(-) diff --git a/gfx/layers/basic/BasicContainerLayer.cpp b/gfx/layers/basic/BasicContainerLayer.cpp index a9bc47fec85a..8f85f3fa1bb8 100644 --- a/gfx/layers/basic/BasicContainerLayer.cpp +++ b/gfx/layers/basic/BasicContainerLayer.cpp @@ -115,6 +115,20 @@ BasicContainerLayer::ChildrenPartitionVisibleRegion(const nsIntRect& aInRect) return covered.Contains(rect); } +void +BasicContainerLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData) +{ + for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) { + BasicImplData* data = ToData(l); + data->Validate(aCallback, aCallbackData); + if (l->GetMaskLayer()) { + data = ToData(l->GetMaskLayer()); + data->Validate(aCallback, aCallbackData); + } + } +} + already_AddRefed BasicLayerManager::CreateContainerLayer() { diff --git a/gfx/layers/basic/BasicContainerLayer.h b/gfx/layers/basic/BasicContainerLayer.h index 7673e28253a4..87be6bb238ed 100644 --- a/gfx/layers/basic/BasicContainerLayer.h +++ b/gfx/layers/basic/BasicContainerLayer.h @@ -76,6 +76,9 @@ public: void SetSupportsComponentAlphaChildren(bool aSupports) { mSupportsComponentAlphaChildren = aSupports; } + virtual void Validate(LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData) MOZ_OVERRIDE; + protected: BasicLayerManager* BasicManager() { diff --git a/gfx/layers/basic/BasicImplData.h b/gfx/layers/basic/BasicImplData.h index 33e278b586c5..7f8a2193f5d2 100644 --- a/gfx/layers/basic/BasicImplData.h +++ b/gfx/layers/basic/BasicImplData.h @@ -73,6 +73,9 @@ public: void* aCallbackData, ReadbackProcessor* aReadback) {} + virtual void Validate(LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData) {} + /** * Layers will get this call when their layer manager is destroyed, this * indicates they should clear resources they don't really need after their diff --git a/gfx/layers/basic/BasicLayerManager.cpp b/gfx/layers/basic/BasicLayerManager.cpp index b5f56f409361..92d7bbeae386 100644 --- a/gfx/layers/basic/BasicLayerManager.cpp +++ b/gfx/layers/basic/BasicLayerManager.cpp @@ -581,22 +581,32 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback, NS_ASSERTION(InConstruction(), "Should be in construction phase"); mPhase = PHASE_DRAWING; - Layer* aLayer = GetRoot(); - RenderTraceLayers(aLayer, "FF00"); + RenderTraceLayers(mRoot, "FF00"); mTransactionIncomplete = false; - if (aFlags & END_NO_COMPOSITE) { - if (!mDummyTarget) { - // XXX: We should really just set mTarget to null and make sure we can handle that further down the call chain - // Creating this temporary surface can be expensive on some platforms (d2d in particular), so cache it between paints. - nsRefPtr surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), GFX_CONTENT_COLOR); - mDummyTarget = new gfxContext(surf); + if (mRoot) { + // Need to do this before we call ApplyDoubleBuffering, + // which depends on correct effective transforms + mSnapEffectiveTransforms = + mTarget ? !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING) : true; + mRoot->ComputeEffectiveTransforms(mTarget ? gfx3DMatrix::From2D(mTarget->CurrentMatrix()) : gfx3DMatrix()); + + ToData(mRoot)->Validate(aCallback, aCallbackData); + if (mRoot->GetMaskLayer()) { + ToData(mRoot->GetMaskLayer())->Validate(aCallback, aCallbackData); + } + + if (aFlags & END_NO_COMPOSITE) { + // Apply pending tree updates before recomputing effective + // properties. + mRoot->ApplyPendingUpdatesToSubtree(); } - mTarget = mDummyTarget; } - if (mTarget && mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) { + if (mTarget && mRoot && + !(aFlags & END_NO_IMMEDIATE_REDRAW) && + !(aFlags & END_NO_COMPOSITE)) { nsIntRect clipRect; { @@ -605,18 +615,6 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback, clipRect = ToOutsideIntRect(mTarget->GetClipExtents()); } - if (aFlags & END_NO_COMPOSITE) { - // Apply pending tree updates before recomputing effective - // properties. - aLayer->ApplyPendingUpdatesToSubtree(); - } - - // Need to do this before we call ApplyDoubleBuffering, - // which depends on correct effective transforms - mSnapEffectiveTransforms = - !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING); - mRoot->ComputeEffectiveTransforms(gfx3DMatrix::From2D(mTarget->CurrentMatrix())); - if (IsRetained()) { nsIntRegion region; MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE); @@ -625,22 +623,12 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback, } } - if (aFlags & END_NO_COMPOSITE) { - if (IsRetained()) { - // Clip the destination out so that we don't draw to it, and - // only end up validating ThebesLayers. - mTarget->Clip(gfxRect(0, 0, 0, 0)); - PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr); - } - // If we're not retained, then don't composite means do nothing at all. - } else { - PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr); - if (mWidget) { - FlashWidgetUpdateArea(mTarget); - } - RenderDebugOverlay(); - LayerManager::PostPresent(); + PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr); + if (mWidget) { + FlashWidgetUpdateArea(mTarget); } + RenderDebugOverlay(); + LayerManager::PostPresent(); if (!mTransactionIncomplete) { // Clear out target if we have a complete transaction. diff --git a/gfx/layers/basic/BasicLayers.h b/gfx/layers/basic/BasicLayers.h index e4fd14219c99..f1320da40f49 100644 --- a/gfx/layers/basic/BasicLayers.h +++ b/gfx/layers/basic/BasicLayers.h @@ -186,7 +186,6 @@ protected: nsRefPtr mDefaultTarget; // The context to draw into. nsRefPtr mTarget; - nsRefPtr mDummyTarget; // Image factory we use. nsRefPtr mFactory; diff --git a/gfx/layers/basic/BasicThebesLayer.cpp b/gfx/layers/basic/BasicThebesLayer.cpp index 6eb5722ebdfd..dd7d146f4394 100644 --- a/gfx/layers/basic/BasicThebesLayer.cpp +++ b/gfx/layers/basic/BasicThebesLayer.cpp @@ -90,21 +90,11 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, NS_ASSERTION(BasicManager()->InDrawing(), "Can only draw in drawing phase"); - if (!mContentClient) { - // we pass a null pointer for the Forwarder argument, which means - // this will not have a ContentHost on the other side. - mContentClient = new ContentClientBasic(nullptr, BasicManager()); - } - nsTArray readbackUpdates; if (aReadback && UsedForReadback()) { aReadback->GetThebesLayerUpdates(this, &readbackUpdates); } - bool canUseOpaqueSurface = CanUseOpaqueSurface(); - ContentType contentType = - canUseOpaqueSurface ? GFX_CONTENT_COLOR : - GFX_CONTENT_COLOR_ALPHA; float opacity = GetEffectiveOpacity(); gfxContext::GraphicsOperator mixBlendMode = GetEffectiveMixBlendMode(); @@ -158,54 +148,6 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, return; } - { - uint32_t flags = 0; -#ifndef MOZ_WIDGET_ANDROID - if (BasicManager()->CompositorMightResample()) { - flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; - } - if (!(flags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE)) { - if (MayResample()) { - flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; - } - } -#endif - if (mDrawAtomically) { - flags |= ThebesLayerBuffer::PAINT_NO_ROTATION; - } - PaintState state = - mContentClient->BeginPaintBuffer(this, contentType, flags); - mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); - - if (state.mContext) { - // The area that became invalid and is visible needs to be repainted - // (this could be the whole visible area if our buffer switched - // from RGB to RGBA, because we might need to repaint with - // subpixel AA) - state.mRegionToInvalidate.And(state.mRegionToInvalidate, - GetEffectiveVisibleRegion()); - nsIntRegion extendedDrawRegion = state.mRegionToDraw; - SetAntialiasingFlags(this, state.mContext); - - RenderTraceInvalidateStart(this, "FFFF00", state.mRegionToDraw.GetBounds()); - - PaintBuffer(state.mContext, - state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate, - state.mDidSelfCopy, - aCallback, aCallbackData); - MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this)); - Mutated(); - - RenderTraceInvalidateEnd(this, "FFFF00"); - } else { - // It's possible that state.mRegionToInvalidate is nonempty here, - // if we are shrinking the valid region to nothing. So use mRegionToDraw - // instead. - NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(), - "No context when we have something to draw, resource exhaustion?"); - } - } - if (BasicManager()->IsTransactionIncomplete()) return; @@ -242,6 +184,72 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, } } +void +BasicThebesLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData) +{ + if (!mContentClient) { + // we pass a null pointer for the Forwarder argument, which means + // this will not have a ContentHost on the other side. + mContentClient = new ContentClientBasic(nullptr, BasicManager()); + } + + if (!BasicManager()->IsRetained()) { + return; + } + + bool canUseOpaqueSurface = CanUseOpaqueSurface(); + ContentType contentType = + canUseOpaqueSurface ? GFX_CONTENT_COLOR : + GFX_CONTENT_COLOR_ALPHA; + + uint32_t flags = 0; +#ifndef MOZ_WIDGET_ANDROID + if (BasicManager()->CompositorMightResample()) { + flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; + } + if (!(flags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE)) { + if (MayResample()) { + flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; + } + } +#endif + if (mDrawAtomically) { + flags |= ThebesLayerBuffer::PAINT_NO_ROTATION; + } + PaintState state = + mContentClient->BeginPaintBuffer(this, contentType, flags); + mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); + + if (state.mContext) { + // The area that became invalid and is visible needs to be repainted + // (this could be the whole visible area if our buffer switched + // from RGB to RGBA, because we might need to repaint with + // subpixel AA) + state.mRegionToInvalidate.And(state.mRegionToInvalidate, + GetEffectiveVisibleRegion()); + nsIntRegion extendedDrawRegion = state.mRegionToDraw; + SetAntialiasingFlags(this, state.mContext); + + RenderTraceInvalidateStart(this, "FFFF00", state.mRegionToDraw.GetBounds()); + + PaintBuffer(state.mContext, + state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate, + state.mDidSelfCopy, + aCallback, aCallbackData); + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this)); + Mutated(); + + RenderTraceInvalidateEnd(this, "FFFF00"); + } else { + // It's possible that state.mRegionToInvalidate is nonempty here, + // if we are shrinking the valid region to nothing. So use mRegionToDraw + // instead. + NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(), + "No context when we have something to draw, resource exhaustion?"); + } +} + already_AddRefed BasicLayerManager::CreateThebesLayer() { diff --git a/gfx/layers/basic/BasicThebesLayer.h b/gfx/layers/basic/BasicThebesLayer.h index 0afc12305f09..af9220dc0fbe 100644 --- a/gfx/layers/basic/BasicThebesLayer.h +++ b/gfx/layers/basic/BasicThebesLayer.h @@ -64,6 +64,9 @@ public: void* aCallbackData, ReadbackProcessor* aReadback); + virtual void Validate(LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData) MOZ_OVERRIDE; + virtual void ClearCachedResources() { if (mContentClient) {