Bug 1057212 - Avoid copying all the tiles when doing PushGroupAndCopyBackground. r=Bas
☠☠ backed out by 6cddb4cf40e3 ☠ ☠
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 01 Sep 2014 15:23:40 +1200
changeset 224477 87494588e4934b55ea92bb08b0eae7ec1962b67f
parent 224476 dc8dc49bba25a56e71ddb932dfd95b701db11eb9
child 224478 da15f68d600a29a95142ef97820a8d1be82c35dc
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs1057212
milestone34.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 1057212 - Avoid copying all the tiles when doing PushGroupAndCopyBackground. r=Bas
gfx/2d/DrawTargetTiled.cpp
gfx/2d/DrawTargetTiled.h
gfx/2d/moz.build
gfx/thebes/gfxContext.cpp
--- a/gfx/2d/DrawTargetTiled.cpp
+++ b/gfx/2d/DrawTargetTiled.cpp
@@ -40,62 +40,16 @@ DrawTargetTiled::Init(const TileSet& aTi
     mRect.y = min(mRect.y, mTiles[i].mTileOrigin.y);
     mRect.width = newXMost - mRect.x;
     mRect.height = newYMost - mRect.y;
   }
   mFormat = mTiles[0].mDrawTarget->GetFormat();
   return true;
 }
 
-class SnapshotTiled : public SourceSurface
-{
-public:
-  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);
-    }
-  }
-
-  virtual SurfaceType GetType() const { return SurfaceType::TILED; }
-  virtual IntSize GetSize() const { return IntSize(mRect.XMost(), mRect.YMost()); }
-  virtual SurfaceFormat GetFormat() const { return mSnapshots[0]->GetFormat(); }
-
-  virtual TemporaryRef<DataSourceSurface> GetDataSurface()
-  {
-    RefPtr<DataSourceSurface> surf = Factory::CreateDataSourceSurface(GetSize(), GetFormat());
-    if (MOZ2D_WARN_IF(!surf)) {
-      return nullptr;
-    }
-
-    DataSourceSurface::MappedSurface mappedSurf;
-    surf->Map(DataSourceSurface::MapType::WRITE, &mappedSurf);
-
-    {
-      RefPtr<DrawTarget> dt =
-        Factory::CreateDrawTargetForData(BackendType::CAIRO, mappedSurf.mData,
-        GetSize(), mappedSurf.mStride, GetFormat());
-
-      for (size_t i = 0; i < mSnapshots.size(); i++) {
-        RefPtr<DataSourceSurface> dataSurf = mSnapshots[i]->GetDataSurface();
-        dt->CopySurface(dataSurf, IntRect(IntPoint(0, 0), mSnapshots[i]->GetSize()), mOrigins[i]);
-      }
-    }
-    surf->Unmap();
-
-    return surf.forget();
-  }
-private:
-  vector<RefPtr<SourceSurface>> mSnapshots;
-  vector<IntPoint> mOrigins;
-  IntRect mRect;
-};
-
 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.
--- a/gfx/2d/DrawTargetTiled.h
+++ b/gfx/2d/DrawTargetTiled.h
@@ -144,12 +144,55 @@ public:
   }
 
 private:
   std::vector<TileInternal> mTiles;
   std::vector<std::vector<uint32_t> > mClippedOutTilesStack;
   IntRect mRect;
 };
 
+class SnapshotTiled : public SourceSurface
+{
+public:
+  SnapshotTiled(const std::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);
+    }
+  }
+
+  virtual SurfaceType GetType() const { return SurfaceType::TILED; }
+  virtual IntSize GetSize() const { return IntSize(mRect.XMost(), mRect.YMost()); }
+  virtual SurfaceFormat GetFormat() const { return mSnapshots[0]->GetFormat(); }
+
+  virtual TemporaryRef<DataSourceSurface> GetDataSurface()
+  {
+    RefPtr<DataSourceSurface> surf = Factory::CreateDataSourceSurface(GetSize(), GetFormat());
+
+    DataSourceSurface::MappedSurface mappedSurf;
+    surf->Map(DataSourceSurface::MapType::WRITE, &mappedSurf);
+
+    {
+      RefPtr<DrawTarget> dt =
+        Factory::CreateDrawTargetForData(BackendType::CAIRO, mappedSurf.mData,
+        GetSize(), mappedSurf.mStride, GetFormat());
+
+      for (size_t i = 0; i < mSnapshots.size(); i++) {
+        RefPtr<DataSourceSurface> dataSurf = mSnapshots[i]->GetDataSurface();
+        dt->CopySurface(dataSurf, IntRect(IntPoint(0, 0), mSnapshots[i]->GetSize()), mOrigins[i]);
+      }
+    }
+    surf->Unmap();
+
+    return surf.forget();
+  }
+
+  std::vector<RefPtr<SourceSurface>> mSnapshots;
+  std::vector<IntPoint> mOrigins;
+  IntRect mRect;
+};
+
 }
 }
 
 #endif
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -16,16 +16,17 @@ EXPORTS.mozilla.gfx += [
     'BasePoint3D.h',
     'BasePoint4D.h',
     'BaseRect.h',
     'BaseSize.h',
     'Blur.h',
     'BorrowedContext.h',
     'Coord.h',
     'DataSurfaceHelpers.h',
+    'DrawTargetTiled.h',
     'Filters.h',
     'Helpers.h',
     'Logging.h',
     'Matrix.h',
     'PathHelpers.h',
     'Point.h',
     'Rect.h',
     'Scale.h',
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -19,16 +19,17 @@
 #include "gfxUtils.h"
 #include "gfxASurface.h"
 #include "gfxPattern.h"
 #include "gfxPlatform.h"
 #include "gfxTeeSurface.h"
 #include "GeckoProfiler.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/PathHelpers.h"
+#include "mozilla/gfx/DrawTargetTiled.h"
 #include <algorithm>
 
 #if CAIRO_HAS_DWRITE_FONT
 #include "gfxWindowsPlatform.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::gfx;
@@ -1113,22 +1114,42 @@ gfxContext::PushGroupAndCopyBackground(g
     DrawTarget *oldDT = mDT;
     RefPtr<SourceSurface> source = mDT->Snapshot();
     Point oldDeviceOffset = CurrentState().deviceOffset;
 
     PushNewDT(gfxContentType::COLOR);
 
     Point offset = CurrentState().deviceOffset - oldDeviceOffset;
     Rect surfRect(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height));
-    Rect sourceRect = surfRect;
-    sourceRect.x += offset.x;
-    sourceRect.y += offset.y;
+    Rect sourceRect = surfRect + offset;
 
     mDT->SetTransform(Matrix());
-    mDT->DrawSurface(source, surfRect, sourceRect);
+
+    // XXX: It's really sad that we have to do this (for performance).
+    // Once DrawTarget gets a PushLayer API we can implement this within
+    // DrawTargetTiled.
+    if (source->GetType() == SurfaceType::TILED) {
+      SnapshotTiled *sourceTiled = static_cast<SnapshotTiled*>(source.get());
+      for (uint32_t i = 0; i < sourceTiled->mSnapshots.size(); i++) {
+        Rect tileSourceRect = sourceRect.Intersect(Rect(sourceTiled->mOrigins[i].x,
+                                                        sourceTiled->mOrigins[i].y,
+                                                        sourceTiled->mSnapshots[i]->GetSize().width,
+                                                        sourceTiled->mSnapshots[i]->GetSize().height));
+
+        if (tileSourceRect.IsEmpty()) {
+          continue;
+        }
+        Rect tileDestRect = tileSourceRect - offset;
+        tileSourceRect -= sourceTiled->mOrigins[i];
+
+        mDT->DrawSurface(sourceTiled->mSnapshots[i], tileDestRect, tileSourceRect);
+      }
+    } else {
+      mDT->DrawSurface(source, surfRect, sourceRect);
+    }
     mDT->SetOpaqueRect(oldDT->GetOpaqueRect());
 
     PushClipsToDT(mDT);
     mDT->SetTransform(GetDTTransform());
     return;
   }
   PushGroup(content);
 }