1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/ops/SoftwarePathRenderer.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
11cb93a386Sopenharmony_ci#include "include/private/SkSemaphore.h"
12cb93a386Sopenharmony_ci#include "src/core/SkTaskGroup.h"
13cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h"
14cb93a386Sopenharmony_ci#include "src/gpu/GrAuditTrail.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrClip.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrDeferredProxyUploader.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrGpuResourcePriv.h"
20cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
21cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h"
22cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h"
23cb93a386Sopenharmony_ci#include "src/gpu/GrSWMaskHelper.h"
24cb93a386Sopenharmony_ci#include "src/gpu/GrUtil.h"
25cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h"
26cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h"
27cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h"
28cb93a386Sopenharmony_ci#include "src/gpu/ops/GrDrawOp.h"
29cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h"
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_cinamespace {
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_ci/**
34cb93a386Sopenharmony_ci * Payload class for use with GrTDeferredProxyUploader. The software path renderer only draws
35cb93a386Sopenharmony_ci * a single path into the mask texture. This stores all of the information needed by the worker
36cb93a386Sopenharmony_ci * thread's call to drawShape (see below, in onDrawPath).
37cb93a386Sopenharmony_ci */
38cb93a386Sopenharmony_ciclass SoftwarePathData {
39cb93a386Sopenharmony_cipublic:
40cb93a386Sopenharmony_ci    SoftwarePathData(const SkIRect& maskBounds, const SkMatrix& viewMatrix,
41cb93a386Sopenharmony_ci                     const GrStyledShape& shape, GrAA aa)
42cb93a386Sopenharmony_ci            : fMaskBounds(maskBounds)
43cb93a386Sopenharmony_ci            , fViewMatrix(viewMatrix)
44cb93a386Sopenharmony_ci            , fShape(shape)
45cb93a386Sopenharmony_ci            , fAA(aa) {}
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci    const SkIRect& getMaskBounds() const { return fMaskBounds; }
48cb93a386Sopenharmony_ci    const SkMatrix* getViewMatrix() const { return &fViewMatrix; }
49cb93a386Sopenharmony_ci    const GrStyledShape& getShape() const { return fShape; }
50cb93a386Sopenharmony_ci    GrAA getAA() const { return fAA; }
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ciprivate:
53cb93a386Sopenharmony_ci    SkIRect fMaskBounds;
54cb93a386Sopenharmony_ci    SkMatrix fViewMatrix;
55cb93a386Sopenharmony_ci    GrStyledShape fShape;
56cb93a386Sopenharmony_ci    GrAA fAA;
57cb93a386Sopenharmony_ci};
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_cibool get_unclipped_shape_dev_bounds(const GrStyledShape& shape, const SkMatrix& matrix,
60cb93a386Sopenharmony_ci                                    SkIRect* devBounds) {
61cb93a386Sopenharmony_ci    SkRect shapeBounds = shape.styledBounds();
62cb93a386Sopenharmony_ci    if (shapeBounds.isEmpty()) {
63cb93a386Sopenharmony_ci        return false;
64cb93a386Sopenharmony_ci    }
65cb93a386Sopenharmony_ci    SkRect shapeDevBounds;
66cb93a386Sopenharmony_ci    matrix.mapRect(&shapeDevBounds, shapeBounds);
67cb93a386Sopenharmony_ci    // Even though these are "unclipped" bounds we still clip to the int32_t range.
68cb93a386Sopenharmony_ci    // This is the largest int32_t that is representable exactly as a float. The next 63 larger ints
69cb93a386Sopenharmony_ci    // would round down to this value when cast to a float, but who really cares.
70cb93a386Sopenharmony_ci    // INT32_MIN is exactly representable.
71cb93a386Sopenharmony_ci    static constexpr int32_t kMaxInt = 2147483520;
72cb93a386Sopenharmony_ci    if (!shapeDevBounds.intersect(SkRect::MakeLTRB(INT32_MIN, INT32_MIN, kMaxInt, kMaxInt))) {
73cb93a386Sopenharmony_ci        return false;
74cb93a386Sopenharmony_ci    }
75cb93a386Sopenharmony_ci    // Make sure that the resulting SkIRect can have representable width and height
76cb93a386Sopenharmony_ci    if (SkScalarRoundToInt(shapeDevBounds.width()) > kMaxInt ||
77cb93a386Sopenharmony_ci        SkScalarRoundToInt(shapeDevBounds.height()) > kMaxInt) {
78cb93a386Sopenharmony_ci        return false;
79cb93a386Sopenharmony_ci    }
80cb93a386Sopenharmony_ci    shapeDevBounds.roundOut(devBounds);
81cb93a386Sopenharmony_ci    return true;
82cb93a386Sopenharmony_ci}
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ciGrSurfaceProxyView make_deferred_mask_texture_view(GrRecordingContext* rContext,
85cb93a386Sopenharmony_ci                                                   SkBackingFit fit,
86cb93a386Sopenharmony_ci                                                   SkISize dimensions) {
87cb93a386Sopenharmony_ci    GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
88cb93a386Sopenharmony_ci    const GrCaps* caps = rContext->priv().caps();
89cb93a386Sopenharmony_ci
90cb93a386Sopenharmony_ci    const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kAlpha_8,
91cb93a386Sopenharmony_ci                                                                 GrRenderable::kNo);
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    GrSwizzle swizzle = caps->getReadSwizzle(format, GrColorType::kAlpha_8);
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci    auto proxy =
96cb93a386Sopenharmony_ci            proxyProvider->createProxy(format, dimensions, GrRenderable::kNo, 1, GrMipmapped::kNo,
97cb93a386Sopenharmony_ci                                       fit, SkBudgeted::kYes, GrProtected::kNo);
98cb93a386Sopenharmony_ci    return {std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle};
99cb93a386Sopenharmony_ci}
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci} // anonymous namespace
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_cinamespace skgpu::v1 {
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
107cb93a386Sopenharmony_ciPathRenderer::CanDrawPath SoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
108cb93a386Sopenharmony_ci    // Pass on any style that applies. The caller will apply the style if a suitable renderer is
109cb93a386Sopenharmony_ci    // not found and try again with the new GrStyledShape.
110cb93a386Sopenharmony_ci    if (!args.fShape->style().applies() && SkToBool(fProxyProvider) &&
111cb93a386Sopenharmony_ci        (args.fAAType == GrAAType::kCoverage || args.fAAType == GrAAType::kNone)) {
112cb93a386Sopenharmony_ci        // This is the fallback renderer for when a path is too complicated for the GPU ones.
113cb93a386Sopenharmony_ci        return CanDrawPath::kAsBackup;
114cb93a386Sopenharmony_ci    }
115cb93a386Sopenharmony_ci    return CanDrawPath::kNo;
116cb93a386Sopenharmony_ci}
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ci// Gets the shape bounds, the clip bounds, and the intersection (if any). Returns false if there
121cb93a386Sopenharmony_ci// is no intersection.
122cb93a386Sopenharmony_cibool SoftwarePathRenderer::GetShapeAndClipBounds(SurfaceDrawContext* sdc,
123cb93a386Sopenharmony_ci                                                 const GrClip* clip,
124cb93a386Sopenharmony_ci                                                 const GrStyledShape& shape,
125cb93a386Sopenharmony_ci                                                 const SkMatrix& matrix,
126cb93a386Sopenharmony_ci                                                 SkIRect* unclippedDevShapeBounds,
127cb93a386Sopenharmony_ci                                                 SkIRect* clippedDevShapeBounds,
128cb93a386Sopenharmony_ci                                                 SkIRect* devClipBounds) {
129cb93a386Sopenharmony_ci    // compute bounds as intersection of rt size, clip, and path
130cb93a386Sopenharmony_ci    *devClipBounds = clip ? clip->getConservativeBounds()
131cb93a386Sopenharmony_ci                          : SkIRect::MakeWH(sdc->width(), sdc->height());
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ci    if (!get_unclipped_shape_dev_bounds(shape, matrix, unclippedDevShapeBounds)) {
134cb93a386Sopenharmony_ci        *unclippedDevShapeBounds = SkIRect::MakeEmpty();
135cb93a386Sopenharmony_ci        *clippedDevShapeBounds = SkIRect::MakeEmpty();
136cb93a386Sopenharmony_ci        return false;
137cb93a386Sopenharmony_ci    }
138cb93a386Sopenharmony_ci    if (!clippedDevShapeBounds->intersect(*devClipBounds, *unclippedDevShapeBounds)) {
139cb93a386Sopenharmony_ci        *clippedDevShapeBounds = SkIRect::MakeEmpty();
140cb93a386Sopenharmony_ci        return false;
141cb93a386Sopenharmony_ci    }
142cb93a386Sopenharmony_ci    return true;
143cb93a386Sopenharmony_ci}
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_civoid SoftwarePathRenderer::DrawNonAARect(SurfaceDrawContext* sdc,
148cb93a386Sopenharmony_ci                                         GrPaint&& paint,
149cb93a386Sopenharmony_ci                                         const GrUserStencilSettings& userStencilSettings,
150cb93a386Sopenharmony_ci                                         const GrClip* clip,
151cb93a386Sopenharmony_ci                                         const SkMatrix& viewMatrix,
152cb93a386Sopenharmony_ci                                         const SkRect& rect,
153cb93a386Sopenharmony_ci                                         const SkMatrix& localMatrix) {
154cb93a386Sopenharmony_ci    sdc->stencilRect(clip, &userStencilSettings, std::move(paint), GrAA::kNo,
155cb93a386Sopenharmony_ci                     viewMatrix, rect, &localMatrix);
156cb93a386Sopenharmony_ci}
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_civoid SoftwarePathRenderer::DrawAroundInvPath(SurfaceDrawContext* sdc,
159cb93a386Sopenharmony_ci                                             GrPaint&& paint,
160cb93a386Sopenharmony_ci                                             const GrUserStencilSettings& userStencilSettings,
161cb93a386Sopenharmony_ci                                             const GrClip* clip,
162cb93a386Sopenharmony_ci                                             const SkMatrix& viewMatrix,
163cb93a386Sopenharmony_ci                                             const SkIRect& devClipBounds,
164cb93a386Sopenharmony_ci                                             const SkIRect& devPathBounds) {
165cb93a386Sopenharmony_ci    SkMatrix invert;
166cb93a386Sopenharmony_ci    if (!viewMatrix.invert(&invert)) {
167cb93a386Sopenharmony_ci        return;
168cb93a386Sopenharmony_ci    }
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci    SkRect rect;
171cb93a386Sopenharmony_ci    if (devClipBounds.fTop < devPathBounds.fTop) {
172cb93a386Sopenharmony_ci        rect.setLTRB(SkIntToScalar(devClipBounds.fLeft),  SkIntToScalar(devClipBounds.fTop),
173cb93a386Sopenharmony_ci                     SkIntToScalar(devClipBounds.fRight), SkIntToScalar(devPathBounds.fTop));
174cb93a386Sopenharmony_ci        DrawNonAARect(sdc, GrPaint::Clone(paint), userStencilSettings, clip,
175cb93a386Sopenharmony_ci                      SkMatrix::I(), rect, invert);
176cb93a386Sopenharmony_ci    }
177cb93a386Sopenharmony_ci    if (devClipBounds.fLeft < devPathBounds.fLeft) {
178cb93a386Sopenharmony_ci        rect.setLTRB(SkIntToScalar(devClipBounds.fLeft), SkIntToScalar(devPathBounds.fTop),
179cb93a386Sopenharmony_ci                     SkIntToScalar(devPathBounds.fLeft), SkIntToScalar(devPathBounds.fBottom));
180cb93a386Sopenharmony_ci        DrawNonAARect(sdc, GrPaint::Clone(paint), userStencilSettings, clip,
181cb93a386Sopenharmony_ci                      SkMatrix::I(), rect, invert);
182cb93a386Sopenharmony_ci    }
183cb93a386Sopenharmony_ci    if (devClipBounds.fRight > devPathBounds.fRight) {
184cb93a386Sopenharmony_ci        rect.setLTRB(SkIntToScalar(devPathBounds.fRight), SkIntToScalar(devPathBounds.fTop),
185cb93a386Sopenharmony_ci                     SkIntToScalar(devClipBounds.fRight), SkIntToScalar(devPathBounds.fBottom));
186cb93a386Sopenharmony_ci        DrawNonAARect(sdc, GrPaint::Clone(paint), userStencilSettings, clip,
187cb93a386Sopenharmony_ci                      SkMatrix::I(), rect, invert);
188cb93a386Sopenharmony_ci    }
189cb93a386Sopenharmony_ci    if (devClipBounds.fBottom > devPathBounds.fBottom) {
190cb93a386Sopenharmony_ci        rect.setLTRB(SkIntToScalar(devClipBounds.fLeft),  SkIntToScalar(devPathBounds.fBottom),
191cb93a386Sopenharmony_ci                     SkIntToScalar(devClipBounds.fRight), SkIntToScalar(devClipBounds.fBottom));
192cb93a386Sopenharmony_ci        DrawNonAARect(sdc, std::move(paint), userStencilSettings, clip,
193cb93a386Sopenharmony_ci                      SkMatrix::I(), rect, invert);
194cb93a386Sopenharmony_ci    }
195cb93a386Sopenharmony_ci}
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_civoid SoftwarePathRenderer::DrawToTargetWithShapeMask(
198cb93a386Sopenharmony_ci        GrSurfaceProxyView view,
199cb93a386Sopenharmony_ci        SurfaceDrawContext* sdc,
200cb93a386Sopenharmony_ci        GrPaint&& paint,
201cb93a386Sopenharmony_ci        const GrUserStencilSettings& userStencilSettings,
202cb93a386Sopenharmony_ci        const GrClip* clip,
203cb93a386Sopenharmony_ci        const SkMatrix& viewMatrix,
204cb93a386Sopenharmony_ci        const SkIPoint& textureOriginInDeviceSpace,
205cb93a386Sopenharmony_ci        const SkIRect& deviceSpaceRectToDraw) {
206cb93a386Sopenharmony_ci    SkMatrix invert;
207cb93a386Sopenharmony_ci    if (!viewMatrix.invert(&invert)) {
208cb93a386Sopenharmony_ci        return;
209cb93a386Sopenharmony_ci    }
210cb93a386Sopenharmony_ci
211cb93a386Sopenharmony_ci    view.concatSwizzle(GrSwizzle("aaaa"));
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ci    SkRect dstRect = SkRect::Make(deviceSpaceRectToDraw);
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_ci    // We use device coords to compute the texture coordinates. We take the device coords and apply
216cb93a386Sopenharmony_ci    // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling
217cb93a386Sopenharmony_ci    // matrix to normalized coords.
218cb93a386Sopenharmony_ci    SkMatrix maskMatrix = SkMatrix::Translate(SkIntToScalar(-textureOriginInDeviceSpace.fX),
219cb93a386Sopenharmony_ci                                              SkIntToScalar(-textureOriginInDeviceSpace.fY));
220cb93a386Sopenharmony_ci    maskMatrix.preConcat(viewMatrix);
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_ci    paint.setCoverageFragmentProcessor(GrTextureEffect::Make(
223cb93a386Sopenharmony_ci            std::move(view), kPremul_SkAlphaType, maskMatrix, GrSamplerState::Filter::kNearest));
224cb93a386Sopenharmony_ci    DrawNonAARect(sdc, std::move(paint), userStencilSettings, clip, SkMatrix::I(),
225cb93a386Sopenharmony_ci                  dstRect, invert);
226cb93a386Sopenharmony_ci}
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
229cb93a386Sopenharmony_ci// return true on success; false on failure
230cb93a386Sopenharmony_cibool SoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
231cb93a386Sopenharmony_ci    GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
232cb93a386Sopenharmony_ci                              "SoftwarePathRenderer::onDrawPath");
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci    if (!fProxyProvider) {
235cb93a386Sopenharmony_ci        return false;
236cb93a386Sopenharmony_ci    }
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ci    SkASSERT(!args.fShape->style().applies());
239cb93a386Sopenharmony_ci    // We really need to know if the shape will be inverse filled or not
240cb93a386Sopenharmony_ci    // If the path is hairline, ignore inverse fill.
241cb93a386Sopenharmony_ci    bool inverseFilled = args.fShape->inverseFilled() &&
242cb93a386Sopenharmony_ci                        !GrIsStrokeHairlineOrEquivalent(args.fShape->style(),
243cb93a386Sopenharmony_ci                                                        *args.fViewMatrix, nullptr);
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci    SkIRect unclippedDevShapeBounds, clippedDevShapeBounds, devClipBounds;
246cb93a386Sopenharmony_ci    // To prevent overloading the cache with entries during animations we limit the cache of masks
247cb93a386Sopenharmony_ci    // to cases where the matrix preserves axis alignment.
248cb93a386Sopenharmony_ci    bool useCache = fAllowCaching && !inverseFilled && args.fViewMatrix->preservesAxisAlignment() &&
249cb93a386Sopenharmony_ci                    args.fShape->hasUnstyledKey() && (GrAAType::kCoverage == args.fAAType);
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_ci    if (!GetShapeAndClipBounds(args.fSurfaceDrawContext,
252cb93a386Sopenharmony_ci                               args.fClip, *args.fShape,
253cb93a386Sopenharmony_ci                               *args.fViewMatrix, &unclippedDevShapeBounds,
254cb93a386Sopenharmony_ci                               &clippedDevShapeBounds,
255cb93a386Sopenharmony_ci                               &devClipBounds)) {
256cb93a386Sopenharmony_ci        if (inverseFilled) {
257cb93a386Sopenharmony_ci            DrawAroundInvPath(args.fSurfaceDrawContext, std::move(args.fPaint),
258cb93a386Sopenharmony_ci                              *args.fUserStencilSettings, args.fClip, *args.fViewMatrix,
259cb93a386Sopenharmony_ci                              devClipBounds, unclippedDevShapeBounds);
260cb93a386Sopenharmony_ci        }
261cb93a386Sopenharmony_ci        return true;
262cb93a386Sopenharmony_ci    }
263cb93a386Sopenharmony_ci
264cb93a386Sopenharmony_ci    const SkIRect* boundsForMask = &clippedDevShapeBounds;
265cb93a386Sopenharmony_ci    if (useCache) {
266cb93a386Sopenharmony_ci        // Use the cache only if >50% of the path is visible.
267cb93a386Sopenharmony_ci        int unclippedWidth = unclippedDevShapeBounds.width();
268cb93a386Sopenharmony_ci        int unclippedHeight = unclippedDevShapeBounds.height();
269cb93a386Sopenharmony_ci        int64_t unclippedArea = sk_64_mul(unclippedWidth, unclippedHeight);
270cb93a386Sopenharmony_ci        int64_t clippedArea = sk_64_mul(clippedDevShapeBounds.width(),
271cb93a386Sopenharmony_ci                                        clippedDevShapeBounds.height());
272cb93a386Sopenharmony_ci        int maxTextureSize = args.fSurfaceDrawContext->caps()->maxTextureSize();
273cb93a386Sopenharmony_ci        if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize ||
274cb93a386Sopenharmony_ci            unclippedHeight > maxTextureSize) {
275cb93a386Sopenharmony_ci            useCache = false;
276cb93a386Sopenharmony_ci        } else {
277cb93a386Sopenharmony_ci            boundsForMask = &unclippedDevShapeBounds;
278cb93a386Sopenharmony_ci        }
279cb93a386Sopenharmony_ci    }
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci    GrUniqueKey maskKey;
282cb93a386Sopenharmony_ci    if (useCache) {
283cb93a386Sopenharmony_ci        // We require the upper left 2x2 of the matrix to match exactly for a cache hit.
284cb93a386Sopenharmony_ci        SkScalar sx = args.fViewMatrix->get(SkMatrix::kMScaleX);
285cb93a386Sopenharmony_ci        SkScalar sy = args.fViewMatrix->get(SkMatrix::kMScaleY);
286cb93a386Sopenharmony_ci        SkScalar kx = args.fViewMatrix->get(SkMatrix::kMSkewX);
287cb93a386Sopenharmony_ci        SkScalar ky = args.fViewMatrix->get(SkMatrix::kMSkewY);
288cb93a386Sopenharmony_ci        static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
289cb93a386Sopenharmony_ci        GrUniqueKey::Builder builder(&maskKey, kDomain, 7 + args.fShape->unstyledKeySize(),
290cb93a386Sopenharmony_ci                                     "SW Path Mask");
291cb93a386Sopenharmony_ci        builder[0] = boundsForMask->width();
292cb93a386Sopenharmony_ci        builder[1] = boundsForMask->height();
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
295cb93a386Sopenharmony_ci        // Fractional translate does not affect caching on Android. This is done for better cache
296cb93a386Sopenharmony_ci        // hit ratio and speed, but it is matching HWUI behavior, which doesn't consider the matrix
297cb93a386Sopenharmony_ci        // at all when caching paths.
298cb93a386Sopenharmony_ci        SkFixed fracX = 0;
299cb93a386Sopenharmony_ci        SkFixed fracY = 0;
300cb93a386Sopenharmony_ci#else
301cb93a386Sopenharmony_ci        SkScalar tx = args.fViewMatrix->get(SkMatrix::kMTransX);
302cb93a386Sopenharmony_ci        SkScalar ty = args.fViewMatrix->get(SkMatrix::kMTransY);
303cb93a386Sopenharmony_ci        // Allow 8 bits each in x and y of subpixel positioning.
304cb93a386Sopenharmony_ci        SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00;
305cb93a386Sopenharmony_ci        SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00;
306cb93a386Sopenharmony_ci#endif
307cb93a386Sopenharmony_ci        builder[2] = SkFloat2Bits(sx);
308cb93a386Sopenharmony_ci        builder[3] = SkFloat2Bits(sy);
309cb93a386Sopenharmony_ci        builder[4] = SkFloat2Bits(kx);
310cb93a386Sopenharmony_ci        builder[5] = SkFloat2Bits(ky);
311cb93a386Sopenharmony_ci        // Distinguish between hairline and filled paths. For hairlines, we also need to include
312cb93a386Sopenharmony_ci        // the cap. (SW grows hairlines by 0.5 pixel with round and square caps). Note that
313cb93a386Sopenharmony_ci        // stroke-and-fill of hairlines is turned into pure fill by SkStrokeRec, so this covers
314cb93a386Sopenharmony_ci        // all cases we might see.
315cb93a386Sopenharmony_ci        uint32_t styleBits = args.fShape->style().isSimpleHairline() ?
316cb93a386Sopenharmony_ci                             ((args.fShape->style().strokeRec().getCap() << 1) | 1) : 0;
317cb93a386Sopenharmony_ci        builder[6] = fracX | (fracY >> 8) | (styleBits << 16);
318cb93a386Sopenharmony_ci        args.fShape->writeUnstyledKey(&builder[7]);
319cb93a386Sopenharmony_ci    }
320cb93a386Sopenharmony_ci
321cb93a386Sopenharmony_ci    GrSurfaceProxyView view;
322cb93a386Sopenharmony_ci    if (useCache) {
323cb93a386Sopenharmony_ci        sk_sp<GrTextureProxy> proxy = fProxyProvider->findOrCreateProxyByUniqueKey(maskKey);
324cb93a386Sopenharmony_ci        if (proxy) {
325cb93a386Sopenharmony_ci            GrSwizzle swizzle = args.fSurfaceDrawContext->caps()->getReadSwizzle(
326cb93a386Sopenharmony_ci                    proxy->backendFormat(), GrColorType::kAlpha_8);
327cb93a386Sopenharmony_ci            view = {std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle};
328cb93a386Sopenharmony_ci            args.fContext->priv().stats()->incNumPathMasksCacheHits();
329cb93a386Sopenharmony_ci        }
330cb93a386Sopenharmony_ci    }
331cb93a386Sopenharmony_ci    if (!view) {
332cb93a386Sopenharmony_ci        SkBackingFit fit = useCache ? SkBackingFit::kExact : SkBackingFit::kApprox;
333cb93a386Sopenharmony_ci        GrAA aa = GrAA(GrAAType::kCoverage == args.fAAType);
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci        SkTaskGroup* taskGroup = nullptr;
336cb93a386Sopenharmony_ci        if (auto direct = args.fContext->asDirectContext()) {
337cb93a386Sopenharmony_ci            taskGroup = direct->priv().getTaskGroup();
338cb93a386Sopenharmony_ci        }
339cb93a386Sopenharmony_ci
340cb93a386Sopenharmony_ci        if (taskGroup) {
341cb93a386Sopenharmony_ci            view = make_deferred_mask_texture_view(args.fContext, fit, boundsForMask->size());
342cb93a386Sopenharmony_ci            if (!view) {
343cb93a386Sopenharmony_ci                return false;
344cb93a386Sopenharmony_ci            }
345cb93a386Sopenharmony_ci
346cb93a386Sopenharmony_ci            auto uploader = std::make_unique<GrTDeferredProxyUploader<SoftwarePathData>>(
347cb93a386Sopenharmony_ci                    *boundsForMask, *args.fViewMatrix, *args.fShape, aa);
348cb93a386Sopenharmony_ci            GrTDeferredProxyUploader<SoftwarePathData>* uploaderRaw = uploader.get();
349cb93a386Sopenharmony_ci
350cb93a386Sopenharmony_ci            auto drawAndUploadMask = [uploaderRaw] {
351cb93a386Sopenharmony_ci                TRACE_EVENT0("skia.gpu", "Threaded SW Mask Render");
352cb93a386Sopenharmony_ci                GrSWMaskHelper helper(uploaderRaw->getPixels());
353cb93a386Sopenharmony_ci                if (helper.init(uploaderRaw->data().getMaskBounds())) {
354cb93a386Sopenharmony_ci                    helper.drawShape(uploaderRaw->data().getShape(),
355cb93a386Sopenharmony_ci                                     *uploaderRaw->data().getViewMatrix(),
356cb93a386Sopenharmony_ci                                     SkRegion::kReplace_Op, uploaderRaw->data().getAA(), 0xFF);
357cb93a386Sopenharmony_ci                } else {
358cb93a386Sopenharmony_ci                    SkDEBUGFAIL("Unable to allocate SW mask.");
359cb93a386Sopenharmony_ci                }
360cb93a386Sopenharmony_ci                uploaderRaw->signalAndFreeData();
361cb93a386Sopenharmony_ci            };
362cb93a386Sopenharmony_ci            taskGroup->add(std::move(drawAndUploadMask));
363cb93a386Sopenharmony_ci            view.asTextureProxy()->texPriv().setDeferredUploader(std::move(uploader));
364cb93a386Sopenharmony_ci        } else {
365cb93a386Sopenharmony_ci            GrSWMaskHelper helper;
366cb93a386Sopenharmony_ci            if (!helper.init(*boundsForMask)) {
367cb93a386Sopenharmony_ci                return false;
368cb93a386Sopenharmony_ci            }
369cb93a386Sopenharmony_ci            helper.drawShape(*args.fShape, *args.fViewMatrix, SkRegion::kReplace_Op, aa, 0xFF);
370cb93a386Sopenharmony_ci            view = helper.toTextureView(args.fContext, fit);
371cb93a386Sopenharmony_ci        }
372cb93a386Sopenharmony_ci
373cb93a386Sopenharmony_ci        if (!view) {
374cb93a386Sopenharmony_ci            return false;
375cb93a386Sopenharmony_ci        }
376cb93a386Sopenharmony_ci        if (useCache) {
377cb93a386Sopenharmony_ci            SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
378cb93a386Sopenharmony_ci
379cb93a386Sopenharmony_ci            // We will add an invalidator to the path so that if the path goes away we will
380cb93a386Sopenharmony_ci            // delete or recycle the mask texture.
381cb93a386Sopenharmony_ci            auto listener = GrMakeUniqueKeyInvalidationListener(&maskKey,
382cb93a386Sopenharmony_ci                                                                args.fContext->priv().contextID());
383cb93a386Sopenharmony_ci            fProxyProvider->assignUniqueKeyToProxy(maskKey, view.asTextureProxy());
384cb93a386Sopenharmony_ci            args.fShape->addGenIDChangeListener(std::move(listener));
385cb93a386Sopenharmony_ci        }
386cb93a386Sopenharmony_ci
387cb93a386Sopenharmony_ci        args.fContext->priv().stats()->incNumPathMasksGenerated();
388cb93a386Sopenharmony_ci    }
389cb93a386Sopenharmony_ci    SkASSERT(view);
390cb93a386Sopenharmony_ci    if (inverseFilled) {
391cb93a386Sopenharmony_ci        DrawAroundInvPath(args.fSurfaceDrawContext, GrPaint::Clone(args.fPaint),
392cb93a386Sopenharmony_ci                          *args.fUserStencilSettings, args.fClip, *args.fViewMatrix, devClipBounds,
393cb93a386Sopenharmony_ci                          unclippedDevShapeBounds);
394cb93a386Sopenharmony_ci    }
395cb93a386Sopenharmony_ci    DrawToTargetWithShapeMask(std::move(view), args.fSurfaceDrawContext, std::move(args.fPaint),
396cb93a386Sopenharmony_ci                              *args.fUserStencilSettings, args.fClip, *args.fViewMatrix,
397cb93a386Sopenharmony_ci                              SkIPoint{boundsForMask->fLeft, boundsForMask->fTop}, *boundsForMask);
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_ci    return true;
400cb93a386Sopenharmony_ci}
401cb93a386Sopenharmony_ci
402cb93a386Sopenharmony_ci} // namespace skgpu::v1
403