Bug 1057212 - Avoid copying all the tiles when doing PushGroupAndCopyBackground. r=Bas
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 03 Sep 2014 09:21:35 +1200
changeset 203277 bb624833b237116f0139d5110c653836043d9fca
parent 203276 2bea22f534f00ef45c0e694a6e0d1c794ec287a8
child 203278 4effa50d89342f598eeea846c5e55b25ebb5b11a
push id27425
push userryanvm@gmail.com
push dateWed, 03 Sep 2014 20:38:59 +0000
treeherdermozilla-central@acbdce59da2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs1057212
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 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
@@ -43,62 +43,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);
 }