Bug 642246 Don't build ThebesLayers for elements with no displayports r=roc
authorBenjamin Stover <bstover@mozilla.com>
Mon, 11 Apr 2011 13:53:01 -0700
changeset 67860 ede9a23ec516
parent 67859 65740bbb1aa8
child 67863 832de5e41bd2
push id19444
push userbstover@mozilla.com
push date2011-04-11 20:48 +0000
treeherdermozilla-central@ede9a23ec516 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs642246
milestone2.2a1pre
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 642246 Don't build ThebesLayers for elements with no displayports r=roc
gfx/layers/Layers.h
layout/base/FrameLayerBuilder.h
layout/base/nsDisplayItemTypes.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/generic/nsGfxScrollFrame.cpp
layout/ipc/RenderFrameParent.cpp
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -758,16 +758,22 @@ public:
 
   /**
    * Dynamic downcast to a Thebes layer. Returns null if this is not
    * a ThebesLayer.
    */
   virtual ThebesLayer* AsThebesLayer() { return nsnull; }
 
   /**
+   * Dynamic cast to a ContainerLayer. Returns null if this is not
+   * a ContainerLayer.
+   */
+  virtual ContainerLayer* AsContainerLayer() { return nsnull; }
+
+  /**
    * Dynamic cast to a ShadowLayer.  Return null if this is not a
    * ShadowLayer.  Can be used anytime.
    */
   virtual ShadowLayer* AsShadowLayer() { return nsnull; }
 
   // These getters can be used anytime.  They return the effective
   // values that should be used when drawing this layer to screen,
   // accounting for this layer possibly being a shadow.
@@ -1024,16 +1030,18 @@ public:
    */
   void SetFrameMetrics(const FrameMetrics& aFrameMetrics)
   {
     mFrameMetrics = aFrameMetrics;
   }
 
   // These getters can be used anytime.
 
+  virtual ContainerLayer* AsContainerLayer() { return this; }
+
   virtual Layer* GetFirstChild() { return mFirstChild; }
   virtual Layer* GetLastChild() { return mLastChild; }
   const FrameMetrics& GetFrameMetrics() { return mFrameMetrics; }
 
   MOZ_LAYER_DECL_NAME("ContainerLayer", TYPE_CONTAINER)
 
   /**
    * ContainerLayer backends need to override ComputeEffectiveTransforms
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -54,17 +54,19 @@ class nsRootPresContext;
 namespace mozilla {
 
 enum LayerState {
   LAYER_NONE,
   LAYER_INACTIVE,
   LAYER_ACTIVE,
   // Force an active layer even if it causes incorrect rendering, e.g.
   // when the layer has rounded rect clips.
-  LAYER_ACTIVE_FORCE
+  LAYER_ACTIVE_FORCE,
+  // Special layer that is metadata only.
+  LAYER_ACTIVE_EMPTY
 };
 
 /**
  * The FrameLayerBuilder belongs to an nsDisplayListBuilder and is
  * responsible for converting display lists into layer trees.
  * 
  * The most important API in this class is BuildContainerLayerFor. This
  * method takes a display list as input and constructs a ContainerLayer
--- a/layout/base/nsDisplayItemTypes.h
+++ b/layout/base/nsDisplayItemTypes.h
@@ -79,16 +79,17 @@ enum Type {
   TYPE_PAGE_SEQUENCE,
   TYPE_PLUGIN,
   TYPE_PLUGIN_READBACK,
   TYPE_PRINT_PREVIEW_BACKGROUND,
   TYPE_PRINT_PLUGIN,
   TYPE_REMOTE,
   TYPE_REMOTE_SHADOW,
   TYPE_SCROLL_LAYER,
+  TYPE_SCROLL_INFO_LAYER,
   TYPE_SELECTION_OVERLAY,
   TYPE_SOLID_COLOR,
   TYPE_TABLE_CELL_BACKGROUND,
   TYPE_TABLE_CELL_SELECTION,
   TYPE_TABLE_ROW_BACKGROUND,
   TYPE_TABLE_ROW_GROUP_BACKGROUND,
   TYPE_TABLE_BORDER_BACKGROUND,
   TYPE_TEXT,
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1831,16 +1831,35 @@ nsDisplayScrollLayer::ComputeVisibility(
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayScrollLayer::~nsDisplayScrollLayer()
 {
   MOZ_COUNT_DTOR(nsDisplayScrollLayer);
 }
 #endif
 
+nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
+  nsDisplayListBuilder* aBuilder,
+  nsDisplayList* aList,
+  nsIFrame* aForFrame,
+  nsIFrame* aViewportFrame)
+  : nsDisplayScrollLayer(aBuilder, aList, aForFrame, aViewportFrame)
+{
+#ifdef NS_BUILD_REFCNT_LOGGING
+  MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer);
+#endif
+}
+
+#ifdef NS_BUILD_REFCNT_LOGGING
+nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
+{
+  MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
+}
+#endif
+
 nsDisplayClip::nsDisplayClip(nsDisplayListBuilder* aBuilder,
                              nsIFrame* aFrame, nsDisplayItem* aItem,
                              const nsRect& aRect)
    : nsDisplayWrapList(aBuilder, aFrame, aItem) {
   MOZ_COUNT_CTOR(nsDisplayClip);
   mClip = SnapBounds(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform(),
                      aBuilder->CurrentPresContext(), aRect);
 }
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1832,16 +1832,40 @@ public:
     // This causes incorrect rendering for rounded clips!
     return mozilla::LAYER_ACTIVE_FORCE;
   }
 private:
   nsIFrame* mViewportFrame;
 };
 
 /**
+ * Like nsDisplayScrollLayer, but only has metadata on the scroll frame. This
+ * creates a layer that has no Thebes child layer, but still allows the
+ * compositor process to know of the scroll frame's existence.
+ */
+class nsDisplayScrollInfoLayer : public nsDisplayScrollLayer
+{
+public:
+  nsDisplayScrollInfoLayer(nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
+                           nsIFrame* aForFrame, nsIFrame* aViewportFrame);
+  NS_DISPLAY_DECL_NAME("ScrollInfoLayer", TYPE_SCROLL_INFO_LAYER)
+
+#ifdef NS_BUILD_REFCNT_LOGGING
+  virtual ~nsDisplayScrollInfoLayer();
+#endif
+
+  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
+                                   LayerManager* aManager)
+  {
+    return mozilla::LAYER_ACTIVE_EMPTY;
+  }
+
+};
+
+/**
  * nsDisplayClip can clip a list of items, but we take a single item
  * initially and then later merge other items into it when we merge
  * adjacent matching nsDisplayClips
  */
 class nsDisplayClip : public nsDisplayWrapList {
 public:
   /**
    * @param aFrame the frame that should be considered the underlying
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1956,55 +1956,68 @@ nsGfxScrollFrameInner::BuildDisplayList(
   // Not all our descendants will be clipped by overflow clipping, but all
   // the ones that aren't clipped will be out of flow frames that have already
   // had dirty rects saved for them by their parent frames calling
   // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our
   // dirty rect here.
   dirtyRect.IntersectRect(aDirtyRect, mScrollPort);
 
   // Override the dirty rectangle if the displayport has been set.
-  nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &dirtyRect);
+  PRBool usingDisplayport =
+    nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &dirtyRect);
 
   nsDisplayListCollection set;
 
   nsPresContext* presContext = mOuter->PresContext();
 
   // Since making new layers is expensive, only use nsDisplayScrollLayer
   // if the area is scrollable.
   //
   // Scroll frames can be generated with a scroll range that is 0, 0.
   // Furthermore, it is not worth the memory tradeoff to allow asynchronous
   // scrolling of small scroll frames. We use an arbitrary minimum scroll
   // range of 20 pixels to eliminate many gfx scroll frames from becoming a
   // layer.
   //
-  PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   nsRect scrollRange = GetScrollRange();
   ScrollbarStyles styles = GetScrollbarStylesFromFrame();
   mShouldBuildLayer =
      (XRE_GetProcessType() == GeckoProcessType_Content &&
      (styles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN ||
       styles.mVertical != NS_STYLE_OVERFLOW_HIDDEN) &&
-     (scrollRange.width >= NSIntPixelsToAppUnits(20, appUnitsPerDevPixel) ||
-      scrollRange.height >= NSIntPixelsToAppUnits(20, appUnitsPerDevPixel))) &&
-     (!mIsRoot || !mOuter->PresContext()->IsRootContentDocument());
+     (!mIsRoot || !mOuter->PresContext()->IsRootContentDocument()));
 
   if (ShouldBuildLayer()) {
-    // Note that using StackingContext breaks z order, so the resulting
-    // rendering can be incorrect for weird edge cases!
-
     nsDisplayList list;
-    rv = mScrolledFrame->BuildDisplayListForStackingContext(
-      aBuilder, dirtyRect + mOuter->GetOffsetTo(mScrolledFrame), &list);
-
-    nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollLayer(
-      aBuilder, &list, mScrolledFrame, mOuter);
-    set.Content()->AppendNewToTop(layerItem);
-  } else
-  {
+    if (usingDisplayport) {
+      // Once a displayport is set, assume that scrolling needs to be fast
+      // so create a layer with all the content inside. The compositor
+      // process will be able to scroll the content asynchronously.
+      //
+      // Note that using StackingContext breaks z order, so the resulting
+      // rendering can be incorrect for weird edge cases!
+
+      rv = mScrolledFrame->BuildDisplayListForStackingContext(
+        aBuilder, dirtyRect + mOuter->GetOffsetTo(mScrolledFrame), &list);
+
+      nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollLayer(
+        aBuilder, &list, mScrolledFrame, mOuter);
+      set.Content()->AppendNewToTop(layerItem);
+    } else {
+      // If there is no displayport set, there is no reason here to force a
+      // layer that needs a memory-expensive allocation, but the compositor
+      // process would still like to know that it exists.
+
+      nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollInfoLayer(
+        aBuilder, &list, mScrolledFrame, mOuter);
+      set.Content()->AppendNewToTop(layerItem);
+
+      rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set);
+    }
+  } else {
     rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   nsRect clip;
   clip = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
 
   nscoord radii[8];
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -134,23 +134,18 @@ FindViewForId(const ViewMap& aMap, ViewI
 {
   ViewMap::const_iterator iter = aMap.find(aId);
   return iter != aMap.end() ? iter->second : NULL;
 }
 
 static const FrameMetrics*
 GetFrameMetrics(Layer* aLayer)
 {
-  // Children are not container layers, so they don't have frame metrics. Give
-  // them a blank metric.
-  if (!aLayer->GetFirstChild())
-    return NULL;
-
-  ContainerLayer* container = static_cast<ContainerLayer*>(aLayer);
-  return &container->GetFrameMetrics();
+  ContainerLayer* container = aLayer->AsContainerLayer();
+  return container ? &container->GetFrameMetrics() : NULL;
 }
 
 static nsIntPoint
 GetRootFrameOffset(nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder)
 {
   nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
 
   // Offset to the content rect in case we have borders or padding
@@ -341,20 +336,19 @@ IsTempLayerManager(LayerManager* aManage
 // aXScale and aYScale are used to calculate any values that need to be in
 // chrome-document CSS pixels and aren't part of the rendering loop, such as
 // the initial scroll offset for a new view.
 static void
 BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews,
              nsFrameLoader* aFrameLoader, Layer* aLayer,
              float aXScale = 1, float aYScale = 1)
 {
-  if (!aLayer->GetFirstChild())
+  ContainerLayer* container = aLayer->AsContainerLayer();
+  if (!container)
     return;
-
-  ContainerLayer* container = static_cast<ContainerLayer*>(aLayer);
   const FrameMetrics metrics = container->GetFrameMetrics();
   const ViewID scrollId = metrics.mScrollId;
 
   if (metrics.IsScrollable()) {
     nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent()
                                         ->PresContext()->AppUnitsPerDevPixel();
     nsContentView* view = FindViewForId(oldContentViews, scrollId);
     if (view) {