Bug 1474883 - Ensure D2D glyph cache is pruned after rendering 1000 transformed glyphs. r=bas, a=RyanVM
authorJamie Nicol <jnicol@mozilla.com>
Thu, 26 Jul 2018 15:23:19 +0100
changeset 449980 151d3c2ef92d9ba9e585728441ac15ddfe1544d1
parent 449979 63f65151b538d6a9a4e363a0688713cdf3761aca
child 449981 a62385e8d213ffa4cf5cbbe820c8ebebbeaa0e23
push id134
push userryanvm@gmail.com
push dateTue, 07 Aug 2018 21:36:59 +0000
treeherdermozilla-esr60@76f13904a547 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, RyanVM
bugs1474883
milestone60.1.1
Bug 1474883 - Ensure D2D glyph cache is pruned after rendering 1000 transformed glyphs. r=bas, a=RyanVM 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. MozReview-Commit-ID: HUFpxDvYAzQ
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -43,16 +43,17 @@ RefPtr<ID2D1Factory1> D2DFactory()
 {
   return DrawTargetD2D1::factory();
 }
 
 DrawTargetD2D1::DrawTargetD2D1()
   : mPushedLayers(1)
   , mSnapshotLock(make_shared<Mutex>("DrawTargetD2D1::mSnapshotLock"))
   , mUsedCommandListsSincePurge(0)
+  , mTransformedGlyphsSinceLastPurge(0)
   , mComplexBlendsWithListInList(0)
   , mDeviceSeq(0)
 {
 }
 
 DrawTargetD2D1::~DrawTargetD2D1()
 {
   PopAllClips();
@@ -152,16 +153,19 @@ DrawTargetD2D1::IntoLuminanceSource(Lumi
  return MakeAndAddRef<SourceSurfaceD2D1>(luminanceOutput, mDC, SurfaceFormat::A8, mSize);
 }
 
 // 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()
 {
   FlushInternal();
 }
 
 void
@@ -701,16 +705,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();
     }
   }
 
@@ -1254,24 +1262,26 @@ DrawTargetD2D1::CleanupD2D()
     mFactory = nullptr;
   }
 }
 
 void
 DrawTargetD2D1::FlushInternal(bool aHasDependencyMutex /* = false */)
 {
   if (IsDeviceContextValid()) {
-    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();
     }
   }
 
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -284,16 +284,17 @@ private:
   RefPtr<SourceSurfaceD2D1> mSnapshot;
   std::shared_ptr<Mutex> mSnapshotLock;
   // 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)
   uint32_t mComplexBlendsWithListInList;
 
   static StaticRefPtr<ID2D1Factory1> mFactory;