Pull blur mask key creation into its own subroutine

draw_shape_with_mask_filter needs to be pulled apart and refactored to
support sharing the result of HW-generated blur masks with DDL recording
threads.

Change-Id: I4b03d5f0cbdd0f12e9740889159d9e91d7f8a060
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/322397
Reviewed-by: Adlai Holler <adlai@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp
index ef4bda0..6ed4303 100644
--- a/src/gpu/GrBlurUtils.cpp
+++ b/src/gpu/GrBlurUtils.cpp
@@ -259,6 +259,92 @@
     return true;
 }
 
+// The key and clip-bounds are computed together because the caching decision can impact the
+// clip-bound.
+// A 'false' return value indicates that the shape is known to be clipped away.
+static bool compute_key_and_clip_bounds(GrUniqueKey* maskKey,
+                                        SkIRect* boundsForClip,
+                                        const GrCaps* caps,
+                                        const SkMatrix& viewMatrix,
+                                        bool inverseFilled,
+                                        const SkMaskFilterBase* maskFilter,
+                                        const GrStyledShape& shape,
+                                        const SkIRect& unclippedDevShapeBounds,
+                                        const SkIRect& devClipBounds) {
+    *boundsForClip = devClipBounds;
+
+#ifndef SK_DISABLE_MASKFILTERED_MASK_CACHING
+    // To prevent overloading the cache with entries during animations we limit the cache of masks
+    // to cases where the matrix preserves axis alignment.
+    bool useCache = !inverseFilled && viewMatrix.preservesAxisAlignment() &&
+                    shape.hasUnstyledKey() && as_MFB(maskFilter)->asABlur(nullptr);
+
+    if (useCache) {
+        SkIRect clippedMaskRect, unClippedMaskRect;
+        maskFilter->canFilterMaskGPU(shape, unclippedDevShapeBounds, devClipBounds,
+                                     viewMatrix, &clippedMaskRect);
+        maskFilter->canFilterMaskGPU(shape, unclippedDevShapeBounds, unclippedDevShapeBounds,
+                                     viewMatrix, &unClippedMaskRect);
+        if (clippedMaskRect.isEmpty()) {
+            return false;
+        }
+
+        // Use the cache only if >50% of the filtered mask is visible.
+        int unclippedWidth = unClippedMaskRect.width();
+        int unclippedHeight = unClippedMaskRect.height();
+        int64_t unclippedArea = sk_64_mul(unclippedWidth, unclippedHeight);
+        int64_t clippedArea = sk_64_mul(clippedMaskRect.width(), clippedMaskRect.height());
+        int maxTextureSize = caps->maxTextureSize();
+        if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize ||
+            unclippedHeight > maxTextureSize) {
+            useCache = false;
+        } else {
+            // Make the clip not affect the mask
+            *boundsForClip = unclippedDevShapeBounds;
+        }
+    }
+
+    if (useCache) {
+        static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+        GrUniqueKey::Builder builder(maskKey, kDomain, 5 + 2 + shape.unstyledKeySize(),
+                                     "Mask Filtered Masks");
+
+        // We require the upper left 2x2 of the matrix to match exactly for a cache hit.
+        SkScalar sx = viewMatrix.get(SkMatrix::kMScaleX);
+        SkScalar sy = viewMatrix.get(SkMatrix::kMScaleY);
+        SkScalar kx = viewMatrix.get(SkMatrix::kMSkewX);
+        SkScalar ky = viewMatrix.get(SkMatrix::kMSkewY);
+        SkScalar tx = viewMatrix.get(SkMatrix::kMTransX);
+        SkScalar ty = viewMatrix.get(SkMatrix::kMTransY);
+        // Allow 8 bits each in x and y of subpixel positioning.
+        SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00;
+        SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00;
+
+        builder[0] = SkFloat2Bits(sx);
+        builder[1] = SkFloat2Bits(sy);
+        builder[2] = SkFloat2Bits(kx);
+        builder[3] = SkFloat2Bits(ky);
+        // Distinguish between hairline and filled paths. For hairlines, we also need to include
+        // the cap. (SW grows hairlines by 0.5 pixel with round and square caps). Note that
+        // stroke-and-fill of hairlines is turned into pure fill by SkStrokeRec, so this covers
+        // all cases we might see.
+        uint32_t styleBits = shape.style().isSimpleHairline()
+                                    ? ((shape.style().strokeRec().getCap() << 1) | 1)
+                                    : 0;
+        builder[4] = fracX | (fracY >> 8) | (styleBits << 16);
+
+        SkMaskFilterBase::BlurRec rec;
+        SkAssertResult(as_MFB(maskFilter)->asABlur(&rec));
+
+        builder[5] = rec.fStyle;  // TODO: we could put this with the other style bits
+        builder[6] = SkFloat2Bits(rec.fSigma);
+        shape.writeUnstyledKey(&builder[7]);
+    }
+#endif
+
+    return true;
+}
+
 static void draw_shape_with_mask_filter(GrRecordingContext* context,
                                         GrRenderTargetContext* renderTargetContext,
                                         const GrClip* clip,
@@ -307,86 +393,24 @@
         }
     }
 
-    // To prevent overloading the cache with entries during animations we limit the cache of masks
-    // to cases where the matrix preserves axis alignment.
-#ifdef SK_DISABLE_MASKFILTERED_MASK_CACHING
-    bool useCache = false;
-#else
-    bool useCache = !inverseFilled && viewMatrix.preservesAxisAlignment() &&
-                    shape->hasUnstyledKey() && as_MFB(maskFilter)->asABlur(nullptr);
-#endif
-
-    const SkIRect* boundsForClip = &devClipBounds;
-    if (useCache) {
-        SkIRect clippedMaskRect, unClippedMaskRect;
-        maskFilter->canFilterMaskGPU(*shape, unclippedDevShapeBounds, devClipBounds,
-                                     viewMatrix, &clippedMaskRect);
-        maskFilter->canFilterMaskGPU(*shape, unclippedDevShapeBounds, unclippedDevShapeBounds,
-                                     viewMatrix, &unClippedMaskRect);
-        if (clippedMaskRect.isEmpty()) {
-            return;
-        }
-
-        // Use the cache only if >50% of the filtered mask is visible.
-        int unclippedWidth = unClippedMaskRect.width();
-        int unclippedHeight = unClippedMaskRect.height();
-        int64_t unclippedArea = sk_64_mul(unclippedWidth, unclippedHeight);
-        int64_t clippedArea = sk_64_mul(clippedMaskRect.width(), clippedMaskRect.height());
-        int maxTextureSize = renderTargetContext->caps()->maxTextureSize();
-        if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize ||
-            unclippedHeight > maxTextureSize) {
-            useCache = false;
-        } else {
-            // Make the clip not affect the mask
-            boundsForClip = &unclippedDevShapeBounds;
-        }
-    }
-
     GrUniqueKey maskKey;
-    if (useCache) {
-        static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
-        GrUniqueKey::Builder builder(&maskKey, kDomain, 5 + 2 + shape->unstyledKeySize(),
-                                     "Mask Filtered Masks");
-
-        // We require the upper left 2x2 of the matrix to match exactly for a cache hit.
-        SkScalar sx = viewMatrix.get(SkMatrix::kMScaleX);
-        SkScalar sy = viewMatrix.get(SkMatrix::kMScaleY);
-        SkScalar kx = viewMatrix.get(SkMatrix::kMSkewX);
-        SkScalar ky = viewMatrix.get(SkMatrix::kMSkewY);
-        SkScalar tx = viewMatrix.get(SkMatrix::kMTransX);
-        SkScalar ty = viewMatrix.get(SkMatrix::kMTransY);
-        // Allow 8 bits each in x and y of subpixel positioning.
-        SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00;
-        SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00;
-
-        builder[0] = SkFloat2Bits(sx);
-        builder[1] = SkFloat2Bits(sy);
-        builder[2] = SkFloat2Bits(kx);
-        builder[3] = SkFloat2Bits(ky);
-        // Distinguish between hairline and filled paths. For hairlines, we also need to include
-        // the cap. (SW grows hairlines by 0.5 pixel with round and square caps). Note that
-        // stroke-and-fill of hairlines is turned into pure fill by SkStrokeRec, so this covers
-        // all cases we might see.
-        uint32_t styleBits = shape->style().isSimpleHairline()
-                                    ? ((shape->style().strokeRec().getCap() << 1) | 1)
-                                    : 0;
-        builder[4] = fracX | (fracY >> 8) | (styleBits << 16);
-
-        SkMaskFilterBase::BlurRec rec;
-        SkAssertResult(as_MFB(maskFilter)->asABlur(&rec));
-
-        builder[5] = rec.fStyle;  // TODO: we could put this with the other style bits
-        builder[6] = SkFloat2Bits(rec.fSigma);
-        shape->writeUnstyledKey(&builder[7]);
+    SkIRect boundsForClip;
+    if (!compute_key_and_clip_bounds(&maskKey, &boundsForClip,
+                                     renderTargetContext->caps(),
+                                     viewMatrix, inverseFilled,
+                                     maskFilter, *shape,
+                                     unclippedDevShapeBounds,
+                                     devClipBounds)) {
+        return;
     }
 
     SkIRect maskRect;
     if (maskFilter->canFilterMaskGPU(*shape,
                                      unclippedDevShapeBounds,
-                                     *boundsForClip,
+                                     boundsForClip,
                                      viewMatrix,
                                      &maskRect)) {
-        if (clip_bounds_quick_reject(*boundsForClip, maskRect)) {
+        if (clip_bounds_quick_reject(boundsForClip, maskRect)) {
             // clipped out
             return;
         }
@@ -433,7 +457,7 @@
     }
 
     sw_draw_with_mask_filter(context, renderTargetContext, clip, viewMatrix, *shape,
-                             maskFilter, *boundsForClip, std::move(paint), maskKey);
+                             maskFilter, boundsForClip, std::move(paint), maskKey);
 }
 
 void GrBlurUtils::drawShapeWithMaskFilter(GrRecordingContext* context,