Bug 922942 - Add a Validate() pass to BasicLayers to avoid needing to create a dummy destination context. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 15 Oct 2013 16:23:21 +1300
changeset 165515 a92cf0787b539b07e2a3711368975ad9746a466a
parent 165514 5133ba07ea89006c7521c3af174b76aa8e636b61
child 165516 b37762151fbd464bec0d58217c935499a1d1f44c
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs922942
milestone27.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
Bug 922942 - Add a Validate() pass to BasicLayers to avoid needing to create a dummy destination context. r=roc
gfx/layers/basic/BasicContainerLayer.cpp
gfx/layers/basic/BasicContainerLayer.h
gfx/layers/basic/BasicImplData.h
gfx/layers/basic/BasicLayerManager.cpp
gfx/layers/basic/BasicLayers.h
gfx/layers/basic/BasicThebesLayer.cpp
gfx/layers/basic/BasicThebesLayer.h
--- a/gfx/layers/basic/BasicContainerLayer.cpp
+++ b/gfx/layers/basic/BasicContainerLayer.cpp
@@ -110,16 +110,30 @@ BasicContainerLayer::ChildrenPartitionVi
     if (!intersection.IsEmpty())
       return false;
     covered.Or(covered, childRegion);
   }
 
   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<ContainerLayer>
 BasicLayerManager::CreateContainerLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ContainerLayer> layer = new BasicContainerLayer(this);
   return layer.forget();
 }
 
--- a/gfx/layers/basic/BasicContainerLayer.h
+++ b/gfx/layers/basic/BasicContainerLayer.h
@@ -71,16 +71,19 @@ public:
    * circumstances.
    */
   bool ChildrenPartitionVisibleRegion(const nsIntRect& aInRect);
 
   void ForceIntermediateSurface() { mUseIntermediateSurface = true; }
 
   void SetSupportsComponentAlphaChildren(bool aSupports) { mSupportsComponentAlphaChildren = aSupports; }
 
+  virtual void Validate(LayerManager::DrawThebesLayerCallback aCallback,
+                        void* aCallbackData) MOZ_OVERRIDE;
+
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 };
 }
 }
--- a/gfx/layers/basic/BasicImplData.h
+++ b/gfx/layers/basic/BasicImplData.h
@@ -68,16 +68,19 @@ public:
    * effective visible region (snapped or unsnapped, it doesn't matter).
    */
   virtual void PaintThebes(gfxContext* aContext,
                            Layer* aMasklayer,
                            LayerManager::DrawThebesLayerCallback aCallback,
                            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
    * LayerManager ceases to exist.
    */
   virtual void ClearCachedResources() {}
 
   /**
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -576,76 +576,64 @@ BasicLayerManager::EndTransactionInterna
 #ifdef MOZ_LAYERS_HAVE_LOG
   MOZ_LAYERS_LOG(("  ----- (beginning paint)"));
   Log();
 #endif
 
   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<gfxASurface> 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);
     }
-    mTarget = mDummyTarget;
+
+    if (aFlags & END_NO_COMPOSITE) {
+      // Apply pending tree updates before recomputing effective
+      // properties.
+      mRoot->ApplyPendingUpdatesToSubtree();
+    }
   }
 
-  if (mTarget && mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
+  if (mTarget && mRoot &&
+      !(aFlags & END_NO_IMMEDIATE_REDRAW) &&
+      !(aFlags & END_NO_COMPOSITE)) {
     nsIntRect clipRect;
 
     {
       gfxContextMatrixAutoSaveRestore save(mTarget);
       mTarget->SetMatrix(gfxMatrix());
       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);
       if (mUsingDefaultTarget && mDoubleBuffering != BUFFER_NONE) {
         ApplyDoubleBuffering(mRoot, clipRect);
       }
     }
 
-    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.
       mTarget = nullptr;
     }
   }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -181,17 +181,16 @@ protected:
 
   // Widget whose surface should be used as the basis for ThebesLayer
   // buffers.
   nsIWidget* mWidget;
   // The default context for BeginTransaction.
   nsRefPtr<gfxContext> mDefaultTarget;
   // The context to draw into.
   nsRefPtr<gfxContext> mTarget;
-  nsRefPtr<gfxContext> mDummyTarget;
   // Image factory we use.
   nsRefPtr<ImageFactory> mFactory;
 
   // Cached surface for double buffering
   gfxCachedTempSurface mCachedSurface;
 
   BufferMode mDoubleBuffering;
   bool mUsingDefaultTarget;
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -85,31 +85,21 @@ BasicThebesLayer::PaintThebes(gfxContext
                               LayerManager::DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               ReadbackProcessor* aReadback)
 {
   PROFILER_LABEL("BasicThebesLayer", "PaintThebes");
   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<ReadbackProcessor::Update> 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();
 
   if (!BasicManager()->IsRetained()) {
     NS_ASSERTION(readbackUpdates.IsEmpty(), "Can't do readback for non-retained layer");
 
     mValidRegion.SetEmpty();
     mContentClient->Clear();
@@ -153,64 +143,16 @@ BasicThebesLayer::PaintThebes(gfxContext
 
       aContext->Restore();
     }
 
     RenderTraceInvalidateEnd(this, "FFFF00");
     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;
 
   gfxRect clipExtents;
   clipExtents = aContext->GetClipExtents();
 
   // Pull out the mask surface and transform here, because the mask
   // is internal to basic layers
@@ -237,16 +179,82 @@ BasicThebesLayer::PaintThebes(gfxContext
       NS_ASSERTION(opacity == 1.0, "Should only read back opaque layers");
       ctx->Translate(gfxPoint(offset.x, offset.y));
       mContentClient->DrawTo(this, ctx, 1.0, maskSurface, maskTransform);
       update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset);
     }
   }
 }
 
+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<ThebesLayer>
 BasicLayerManager::CreateThebesLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ThebesLayer> layer = new BasicThebesLayer(this);
   return layer.forget();
 }
 
--- a/gfx/layers/basic/BasicThebesLayer.h
+++ b/gfx/layers/basic/BasicThebesLayer.h
@@ -59,16 +59,19 @@ public:
   }
 
   virtual void PaintThebes(gfxContext* aContext,
                            Layer* aMaskLayer,
                            LayerManager::DrawThebesLayerCallback aCallback,
                            void* aCallbackData,
                            ReadbackProcessor* aReadback);
 
+  virtual void Validate(LayerManager::DrawThebesLayerCallback aCallback,
+                        void* aCallbackData) MOZ_OVERRIDE;
+
   virtual void ClearCachedResources()
   {
     if (mContentClient) {
       mContentClient->Clear();
     }
     mValidRegion.SetEmpty();
   }