Bug 1474883 - Ensure D2D glyph cache is pruned after rendering 1000 transformed glyphs. r=bas, a=IanN CLOSED TREE DONTBUILD SEAMONKEY_2_49_ESR_RELBRANCH
authorJamie Nicol <jnicol@mozilla.com>
Thu, 26 Jul 2018 15:23:19 +0100
branchSEAMONKEY_2_49_ESR_RELBRANCH
changeset 357532 da9a857954e8b0229b9ec9183bc9208be5343edb
parent 357531 9969693fb395970df19a7e4e99b72d97e7963f10
child 357533 5205eb5a7d31cad2b623be3bbe187066384faf24
push id7834
push userfrgrahl@gmx.net
push dateSun, 13 Jan 2019 12:17:02 +0000
treeherdermozilla-esr52@6e4ad8a8f2e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, IanN
bugs1474883
milestone52.9.1
Bug 1474883 - Ensure D2D glyph cache is pruned after rendering 1000 transformed glyphs. r=bas, a=IanN CLOSED TREE DONTBUILD mozilla-esr52 SEAMONKEY_2_49_ESR_RELBRANCH Rendering glyphs at many different rotations was causing the D2D glyph cache to grow very large. Calling EndDraw/BeginDraw will prune the cache, but is costly, so only do it for every 1000 glyphs.
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -36,16 +36,17 @@ ID2D1Factory1* DrawTargetD2D1::mFactory 
 ID2D1Factory1 *D2DFactory1()
 {
   return DrawTargetD2D1::factory();
 }
 
 DrawTargetD2D1::DrawTargetD2D1()
   : mPushedLayers(1)
   , mUsedCommandListsSincePurge(0)
+  , mTransformedGlyphsSinceLastPurge(0)
   , mDidComplexBlendWithListInList(false)
 {
 }
 
 DrawTargetD2D1::~DrawTargetD2D1()
 {
   PopAllClips();
 
@@ -97,28 +98,33 @@ DrawTargetD2D1::Snapshot()
   return snapshot.forget();
 }
 
 // Command lists are kept around by device contexts until EndDraw is called,
 // this can cause issues with memory usage (see bug 1238328). EndDraw/BeginDraw
 // are expensive though, especially relatively when little work is done, so
 // we try to reduce the amount of times we execute these purges.
 static const uint32_t kPushedLayersBeforePurge = 25;
+// Rendering glyphs with different transforms causes the glyph cache to grow
+// very large (see bug 1474883) so we must call EndDraw every so often.
+static const uint32_t kTransformedGlyphsBeforePurge = 1000;
 
 void
 DrawTargetD2D1::Flush()
 {
-  if ((mUsedCommandListsSincePurge >= kPushedLayersBeforePurge) &&
+  if ((mUsedCommandListsSincePurge >= kPushedLayersBeforePurge ||
+       mTransformedGlyphsSinceLastPurge >= kTransformedGlyphsBeforePurge) &&
       mPushedLayers.size() == 1) {
     // It's important to pop all clips as otherwise layers can forget about
     // their clip when doing an EndDraw. When we have layers pushed we cannot
     // easily pop all underlying clips to delay the purge until we have no
     // layers pushed.
     PopAllClips();
     mUsedCommandListsSincePurge = 0;
+    mTransformedGlyphsSinceLastPurge = 0;
     mDC->EndDraw();
     mDC->BeginDraw();
   } else {
     mDC->Flush();
   }
 
   // We no longer depend on any target.
   for (TargetSet::iterator iter = mDependingOnTargets.begin();
@@ -640,16 +646,20 @@ DrawTargetD2D1::FillGlyphs(ScaledFont *a
       mDC->SetTransform(D2DMatrix(mTransform));
     }
   }
 
   if (brush) {
     mDC->DrawGlyphRun(D2D1::Point2F(), &autoRun, brush);
   }
 
+  if (mTransform.HasNonTranslation()) {
+    mTransformedGlyphsSinceLastPurge += aBuffer.mNumGlyphs;
+  }
+
   if (needsRepushedLayers) {
     PopClipsFromDC(mDC);
 
     if (!mTransform.IsRectilinear()) {
       mDC->PopLayer();
     }
   }
 
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -275,16 +275,17 @@ private:
   // target is modified. We keep it alive as a cache.
   RefPtr<SourceSurfaceD2D1> mSnapshot;
   // A list of targets we need to flush when we're modified.
   TargetSet mDependentTargets;
   // A list of targets which have this object in their mDependentTargets set
   TargetSet mDependingOnTargets;
 
   uint32_t mUsedCommandListsSincePurge;
+  uint32_t mTransformedGlyphsSinceLastPurge;
   // When a BlendEffect has been drawn to a command list, and that command list is
   // subsequently used -again- as an input to a blend effect for a command list,
   // this causes an infinite recursion inside D2D as it tries to resolve the bounds.
   // If we resolve the current command list before this happens
   // we can avoid the subsequent hang. (See bug 1293586)
   bool mDidComplexBlendWithListInList;
 
   static ID2D1Factory1 *mFactory;