make producing GrTextBlob sub runs thread safe

Change-Id: Ie16e41fa6cef2d06d1e6e82036524dd5ad06b1ed
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/375036
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/gpu/GrSurfaceDrawContext.cpp b/src/gpu/GrSurfaceDrawContext.cpp
index dff2642..3803946 100644
--- a/src/gpu/GrSurfaceDrawContext.cpp
+++ b/src/gpu/GrSurfaceDrawContext.cpp
@@ -429,18 +429,15 @@
             textBlobCache->add(glyphRunList, blob);
         }
 
-        // TODO(herb): redo processGlyphRunList to handle shifted draw matrix.
         bool supportsSDFT = fContext->priv().caps()->shaderCaps()->supportsDistanceFieldText();
-        for (auto& glyphRun : glyphRunList) {
-            fGlyphPainter.processGlyphRun(glyphRun,
-                                          viewMatrix.localToDevice(),
-                                          drawOrigin,
-                                          drawPaint,
-                                          fSurfaceProps,
-                                          supportsSDFT,
-                                          options,
-                                          blob.get());
-        }
+        blob->makeSubRuns(&fGlyphPainter,
+                          glyphRunList,
+                          viewMatrix.localToDevice(),
+                          drawOrigin,
+                          drawPaint,
+                          fSurfaceProps,
+                          supportsSDFT,
+                          options);
     }
 
     for (const GrSubRun& subRun : blob->subRunList()) {
diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp
index 29f2fc3..f662da1 100644
--- a/src/gpu/text/GrTextBlob.cpp
+++ b/src/gpu/text/GrTextBlob.cpp
@@ -1480,6 +1480,30 @@
         , fInitialMatrix{drawMatrix}
         , fInitialLuminance{initialLuminance} { }
 
+void GrTextBlob::makeSubRuns(SkGlyphRunListPainter* painter,
+                             const SkGlyphRunList& glyphRunList,
+                             const SkMatrix& drawMatrix,
+                             SkPoint drawOrigin,
+                             const SkPaint& runPaint,
+                             const SkSurfaceProps& props,
+                             bool contextSupportsDistanceFieldText,
+                             const GrSDFTOptions& options) {
+    SkAutoSpinlock lock{fSpinLock};
+    if (!fSubRunsCreated) {
+        for (auto& glyphRun : glyphRunList) {
+            painter->processGlyphRun(glyphRun,
+                                     drawMatrix,
+                                     drawOrigin,
+                                     runPaint,
+                                     props,
+                                     contextSupportsDistanceFieldText,
+                                     options,
+                                     this);
+        }
+        fSubRunsCreated = true;
+    }
+}
+
 void GrTextBlob::processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
                                     const SkStrikeSpec& strikeSpec) {
 
diff --git a/src/gpu/text/GrTextBlob.h b/src/gpu/text/GrTextBlob.h
index 0e8431e..28aa46f 100644
--- a/src/gpu/text/GrTextBlob.h
+++ b/src/gpu/text/GrTextBlob.h
@@ -399,6 +399,16 @@
     void* operator new(size_t);
     void* operator new(size_t, void* p);
 
+    void makeSubRuns(
+            SkGlyphRunListPainter* painter,
+            const SkGlyphRunList& glyphRunList,
+            const SkMatrix& drawMatrix,
+            SkPoint drawOrigin,
+            const SkPaint& runPaint,
+            const SkSurfaceProps& props,
+            bool contextSupportsDistanceFieldText,
+            const GrSDFTOptions& options) SK_EXCLUDES(fSpinLock);
+
     static const Key& GetKey(const GrTextBlob& blob);
     static uint32_t Hash(const Key& key);
 
@@ -442,6 +452,14 @@
     void processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
                             const SkStrikeSpec& strikeSpec) override;
 
+    // The run must be created only once.
+    bool fSubRunsCreated SK_GUARDED_BY(fSpinLock) {false};
+
+    // This lock guards makeSubRuns, but also guards addMultiMaskFormat, processDeviceMasks,
+    // processSourcePaths, processSourceSDFT, and processSourceMasks. These are callbacks, and
+    // there is no way for the annotation system to track the lock through processGlyphRun.
+    mutable SkSpinlock fSpinLock;
+
     // The allocator must come first because it needs to be destroyed last. Other fields of this
     // structure may have pointers into it.
     GrSubRunAllocator fAlloc;