Bug 1059033 - Part 3: Avoid save/restoring for tiles that are entirely clipped out. r=Bas
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 03 Sep 2014 09:20:44 +1200
changeset 226488 04f6cbbcd1bcd3a770195041dad50129791395c6
parent 226487 dae2525a189c25147e811da3fd932efa48922faf
child 226489 e96c73e49d5869941c14fc5e42b20b7e114d3e7a
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs1059033
milestone35.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 1059033 - Part 3: Avoid save/restoring for tiles that are entirely clipped out. r=Bas
gfx/2d/DrawTargetTiled.cpp
gfx/2d/DrawTargetTiled.h
--- a/gfx/2d/DrawTargetTiled.cpp
+++ b/gfx/2d/DrawTargetTiled.cpp
@@ -46,17 +46,17 @@ DrawTargetTiled::Init(const TileSet& aTi
   }
   mFormat = mTiles[0].mDrawTarget->GetFormat();
   return true;
 }
 
 class SnapshotTiled : public SourceSurface
 {
 public:
-  SnapshotTiled(const vector<Tile>& aTiles, const IntRect& aRect)
+  SnapshotTiled(const vector<TileInternal>& aTiles, const IntRect& aRect)
     : mRect(aRect)
   {
     for (size_t i = 0; i < aTiles.size(); i++) {
       mSnapshots.push_back(aTiles[i].mDrawTarget->Snapshot());
       mOrigins.push_back(aTiles[i].mTileOrigin);
     }
   }
 
@@ -95,78 +95,134 @@ private:
 };
 
 TemporaryRef<SourceSurface>
 DrawTargetTiled::Snapshot()
 {
   return new SnapshotTiled(mTiles, mRect);
 }
 
+// Skip the mClippedOut check since this is only used for Flush() which
+// should happen even if we're clipped.
 #define TILED_COMMAND(command) \
   void \
   DrawTargetTiled::command() \
   { \
     for (size_t i = 0; i < mTiles.size(); i++) { \
-    \
-    \
-    mTiles[i].mDrawTarget->command(); \
+      mTiles[i].mDrawTarget->command(); \
     } \
   }
 #define TILED_COMMAND1(command, type1) \
   void \
   DrawTargetTiled::command(type1 arg1) \
   { \
     for (size_t i = 0; i < mTiles.size(); i++) { \
-    \
-    \
-    mTiles[i].mDrawTarget->command(arg1); \
+      if (!mTiles[i].mClippedOut) \
+        mTiles[i].mDrawTarget->command(arg1); \
     } \
   }
 #define TILED_COMMAND3(command, type1, type2, type3) \
   void \
   DrawTargetTiled::command(type1 arg1, type2 arg2, type3 arg3) \
   { \
     for (size_t i = 0; i < mTiles.size(); i++) { \
-    \
-    \
-    mTiles[i].mDrawTarget->command(arg1, arg2, arg3); \
+      if (!mTiles[i].mClippedOut) \
+        mTiles[i].mDrawTarget->command(arg1, arg2, arg3); \
     } \
   }
 #define TILED_COMMAND4(command, type1, type2, type3, type4) \
   void \
   DrawTargetTiled::command(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
   { \
     for (size_t i = 0; i < mTiles.size(); i++) { \
-    \
-    \
-    mTiles[i].mDrawTarget->command(arg1, arg2, arg3, arg4); \
+      if (!mTiles[i].mClippedOut) \
+        mTiles[i].mDrawTarget->command(arg1, arg2, arg3, arg4); \
     } \
   }
 #define TILED_COMMAND5(command, type1, type2, type3, type4, type5) \
   void \
   DrawTargetTiled::command(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
   { \
     for (size_t i = 0; i < mTiles.size(); i++) { \
-    \
-    \
-    mTiles[i].mDrawTarget->command(arg1, arg2, arg3, arg4, arg5); \
+      if (!mTiles[i].mClippedOut) \
+        mTiles[i].mDrawTarget->command(arg1, arg2, arg3, arg4, arg5); \
     } \
   }
 
 TILED_COMMAND(Flush)
 TILED_COMMAND4(DrawFilter, FilterNode*, const Rect&, const Point&, const DrawOptions&)
 TILED_COMMAND1(ClearRect, const Rect&)
 TILED_COMMAND4(MaskSurface, const Pattern&, SourceSurface*, Point, const DrawOptions&)
 TILED_COMMAND4(StrokeRect, const Rect&, const Pattern&, const StrokeOptions&, const DrawOptions&)
 TILED_COMMAND5(StrokeLine, const Point&, const Point&, const Pattern&, const StrokeOptions&, const DrawOptions&)
 TILED_COMMAND5(FillGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&, const DrawOptions&, const GlyphRenderingOptions*)
 TILED_COMMAND3(Mask, const Pattern&, const Pattern&, const DrawOptions&)
-TILED_COMMAND1(PushClip, const Path*)
-TILED_COMMAND1(PushClipRect, const Rect&)
-TILED_COMMAND(PopClip)
+
+void
+DrawTargetTiled::PushClip(const Path* aPath)
+{
+  mClippedOutTilesStack.push_back(std::vector<uint32_t>());
+  std::vector<uint32_t>& clippedTiles = mClippedOutTilesStack.back();
+
+  Rect deviceRect = aPath->GetBounds(mTransform);
+
+  for (size_t i = 0; i < mTiles.size(); i++) {
+    if (!mTiles[i].mClippedOut) {
+      if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
+                                   mTiles[i].mTileOrigin.y,
+                                   mTiles[i].mDrawTarget->GetSize().width,
+                                   mTiles[i].mDrawTarget->GetSize().height))) {
+        mTiles[i].mDrawTarget->PushClip(aPath);
+      } else {
+        mTiles[i].mClippedOut = true;
+        clippedTiles.push_back(i);
+      }
+    }
+  }
+}
+
+void
+DrawTargetTiled::PushClipRect(const Rect& aRect)
+{
+  mClippedOutTilesStack.push_back(std::vector<uint32_t>());
+  std::vector<uint32_t>& clippedTiles = mClippedOutTilesStack.back();
+
+  Rect deviceRect = mTransform.TransformBounds(aRect);
+
+  for (size_t i = 0; i < mTiles.size(); i++) {
+    if (!mTiles[i].mClippedOut) {
+      if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
+                                   mTiles[i].mTileOrigin.y,
+                                   mTiles[i].mDrawTarget->GetSize().width,
+                                   mTiles[i].mDrawTarget->GetSize().height))) {
+        mTiles[i].mDrawTarget->PushClipRect(aRect);
+      } else {
+        mTiles[i].mClippedOut = true;
+        clippedTiles.push_back(i);
+      }
+    }
+  }
+}
+
+void
+DrawTargetTiled::PopClip()
+{
+  for (size_t i = 0; i < mTiles.size(); i++) {
+    if (!mTiles[i].mClippedOut) {
+      mTiles[i].mDrawTarget->PopClip();
+    }
+  }
+
+  std::vector<uint32_t>& clippedTiles = mClippedOutTilesStack.back();
+  for (size_t i = 0; i < clippedTiles.size(); i++) {
+    mTiles[clippedTiles[i]].mClippedOut = false;
+  }
+
+  mClippedOutTilesStack.pop_back();
+}
 
 void
 DrawTargetTiled::CopySurface(SourceSurface *aSurface,
                              const IntRect &aSourceRect,
                              const IntPoint &aDestination)
 {
   // CopySurface ignores the transform, account for that here.
   for (size_t i = 0; i < mTiles.size(); i++) {
@@ -195,31 +251,33 @@ DrawTargetTiled::SetTransform(const Matr
   DrawTarget::SetTransform(aTransform);
 }
 
 void
 DrawTargetTiled::DrawSurface(SourceSurface* aSurface, const Rect& aDest, const Rect& aSource, const DrawSurfaceOptions& aSurfaceOptions, const DrawOptions& aDrawOptions)
 {
   Rect deviceRect = mTransform.TransformBounds(aDest);
   for (size_t i = 0; i < mTiles.size(); i++) {
-    if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
+    if (!mTiles[i].mClippedOut &&
+        deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
                                    mTiles[i].mTileOrigin.y,
                                    mTiles[i].mDrawTarget->GetSize().width,
                                    mTiles[i].mDrawTarget->GetSize().height))) {
       mTiles[i].mDrawTarget->DrawSurface(aSurface, aDest, aSource, aSurfaceOptions, aDrawOptions);
     }
   }
 }
 
 void
 DrawTargetTiled::FillRect(const Rect& aRect, const Pattern& aPattern, const DrawOptions& aDrawOptions)
 {
   Rect deviceRect = mTransform.TransformBounds(aRect);
   for (size_t i = 0; i < mTiles.size(); i++) {
-    if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
+    if (!mTiles[i].mClippedOut &&
+        deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
                                    mTiles[i].mTileOrigin.y,
                                    mTiles[i].mDrawTarget->GetSize().width,
                                    mTiles[i].mDrawTarget->GetSize().height))) {
       mTiles[i].mDrawTarget->FillRect(aRect, aPattern, aDrawOptions);
     }
   }
 }
 
@@ -253,31 +311,33 @@ PathExtentsToMaxStrokeExtents(const Stro
 void
 DrawTargetTiled::Stroke(const Path* aPath, const Pattern& aPattern, const StrokeOptions& aStrokeOptions, const DrawOptions& aDrawOptions)
 {
   // Approximate the stroke extents, since Path::GetStrokeExtents can be slow
   Rect deviceRect = PathExtentsToMaxStrokeExtents(aStrokeOptions,
                                                  aPath->GetBounds(mTransform),
                                                  mTransform);
   for (size_t i = 0; i < mTiles.size(); i++) {
-    if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
+    if (!mTiles[i].mClippedOut &&
+        deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
                                    mTiles[i].mTileOrigin.y,
                                    mTiles[i].mDrawTarget->GetSize().width,
                                    mTiles[i].mDrawTarget->GetSize().height))) {
       mTiles[i].mDrawTarget->Stroke(aPath, aPattern, aStrokeOptions, aDrawOptions);
     }
   }
 }
 
 void
 DrawTargetTiled::Fill(const Path* aPath, const Pattern& aPattern, const DrawOptions& aDrawOptions)
 {
   Rect deviceRect = aPath->GetBounds(mTransform);
   for (size_t i = 0; i < mTiles.size(); i++) {
-    if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
+    if (!mTiles[i].mClippedOut &&
+        deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
                                    mTiles[i].mTileOrigin.y,
                                    mTiles[i].mDrawTarget->GetSize().width,
                                    mTiles[i].mDrawTarget->GetSize().height))) {
       mTiles[i].mDrawTarget->Fill(aPath, aPattern, aDrawOptions);
     }
   }
 }
 
--- a/gfx/2d/DrawTargetTiled.h
+++ b/gfx/2d/DrawTargetTiled.h
@@ -9,16 +9,30 @@
 #include "2D.h"
 #include "Filters.h"
 
 #include <vector>
 
 namespace mozilla {
 namespace gfx {
 
+struct TileInternal : public Tile {
+  TileInternal()
+    : mClippedOut(false)
+  {}
+
+  TileInternal(const Tile& aOther)
+    : Tile(aOther)
+    , mClippedOut(false)
+  {}
+
+  bool mClippedOut;
+};
+
+
 class DrawTargetTiled : public DrawTarget
 {
 public:
   DrawTargetTiled();
 
   bool Init(const TileSet& mTiles);
 
   virtual bool IsTiledDrawTarget() const { return true; }
@@ -125,16 +139,17 @@ public:
     return mTiles[0].mDrawTarget->CreateGradientStops(aStops, aNumStops, aExtendMode);
   }
   virtual TemporaryRef<FilterNode> CreateFilter(FilterType aType)
   {
     return mTiles[0].mDrawTarget->CreateFilter(aType);
   }
 
 private:
-  std::vector<Tile> mTiles;
+  std::vector<TileInternal> mTiles;
+  std::vector<std::vector<uint32_t> > mClippedOutTilesStack;
   IntRect mRect;
 };
 
 }
 }
 
 #endif