1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 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/FillRRectOp.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h"
11cb93a386Sopenharmony_ci#include "src/core/SkRRectPriv.h"
12cb93a386Sopenharmony_ci#include "src/gpu/BufferWriter.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h"
14cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrOpsRenderPass.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h"
20cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h"
21cb93a386Sopenharmony_ci#include "src/gpu/GrVx.h"
22cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrShape.h"
23cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
24cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h"
25cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
26cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h"
27cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_cinamespace skgpu::v1::FillRRectOp {
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_cinamespace {
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_ciclass FillRRectOpImpl final : public GrMeshDrawOp {
34cb93a386Sopenharmony_ciprivate:
35cb93a386Sopenharmony_ci    using Helper = GrSimpleMeshDrawOpHelper;
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_cipublic:
38cb93a386Sopenharmony_ci    DEFINE_OP_CLASS_ID
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci    static GrOp::Owner Make(GrRecordingContext*,
41cb93a386Sopenharmony_ci                            SkArenaAlloc*,
42cb93a386Sopenharmony_ci                            GrPaint&&,
43cb93a386Sopenharmony_ci                            const SkMatrix& viewMatrix,
44cb93a386Sopenharmony_ci                            const SkRRect&,
45cb93a386Sopenharmony_ci                            const SkRect& localRect,
46cb93a386Sopenharmony_ci                            GrAA);
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ci    const char* name() const override { return "FillRRectOp"; }
49cb93a386Sopenharmony_ci
50cb93a386Sopenharmony_ci    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci    ClipResult clipToShape(skgpu::v1::SurfaceDrawContext*,
53cb93a386Sopenharmony_ci                           SkClipOp,
54cb93a386Sopenharmony_ci                           const SkMatrix& clipMatrix,
55cb93a386Sopenharmony_ci                           const GrShape&,
56cb93a386Sopenharmony_ci                           GrAA) override;
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override;
59cb93a386Sopenharmony_ci    CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override;
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    void visitProxies(const GrVisitProxyFunc& func) const override {
62cb93a386Sopenharmony_ci        if (fProgramInfo) {
63cb93a386Sopenharmony_ci            fProgramInfo->visitFPProxies(func);
64cb93a386Sopenharmony_ci        } else {
65cb93a386Sopenharmony_ci            fHelper.visitProxies(func);
66cb93a386Sopenharmony_ci        }
67cb93a386Sopenharmony_ci    }
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci    void onPrepareDraws(GrMeshDrawTarget*) override;
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ci    void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ciprivate:
74cb93a386Sopenharmony_ci    friend class ::GrSimpleMeshDrawOpHelper; // for access to ctor
75cb93a386Sopenharmony_ci    friend class ::GrOp;         // for access to ctor
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_ci    enum class ProcessorFlags {
78cb93a386Sopenharmony_ci        kNone             = 0,
79cb93a386Sopenharmony_ci        kUseHWDerivatives = 1 << 0,
80cb93a386Sopenharmony_ci        kHasLocalCoords   = 1 << 1,
81cb93a386Sopenharmony_ci        kWideColor        = 1 << 2,
82cb93a386Sopenharmony_ci        kMSAAEnabled      = 1 << 3,
83cb93a386Sopenharmony_ci        kFakeNonAA        = 1 << 4,
84cb93a386Sopenharmony_ci    };
85cb93a386Sopenharmony_ci    constexpr static int kNumProcessorFlags = 5;
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci    GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(ProcessorFlags);
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci    class Processor;
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci    FillRRectOpImpl(GrProcessorSet*,
92cb93a386Sopenharmony_ci                    const SkPMColor4f& paintColor,
93cb93a386Sopenharmony_ci                    SkArenaAlloc*,
94cb93a386Sopenharmony_ci                    const SkMatrix& viewMatrix,
95cb93a386Sopenharmony_ci                    const SkRRect&,
96cb93a386Sopenharmony_ci                    const SkRect& localRect,
97cb93a386Sopenharmony_ci                    ProcessorFlags);
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    GrProgramInfo* programInfo() override { return fProgramInfo; }
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci    // Create a GrProgramInfo object in the provided arena
102cb93a386Sopenharmony_ci    void onCreateProgramInfo(const GrCaps*,
103cb93a386Sopenharmony_ci                             SkArenaAlloc*,
104cb93a386Sopenharmony_ci                             const GrSurfaceProxyView& writeView,
105cb93a386Sopenharmony_ci                             bool usesMSAASurface,
106cb93a386Sopenharmony_ci                             GrAppliedClip&&,
107cb93a386Sopenharmony_ci                             const GrDstProxyView&,
108cb93a386Sopenharmony_ci                             GrXferBarrierFlags renderPassXferBarriers,
109cb93a386Sopenharmony_ci                             GrLoadOp colorLoadOp) override;
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ci    Helper         fHelper;
112cb93a386Sopenharmony_ci    ProcessorFlags fProcessorFlags;
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_ci    struct Instance {
115cb93a386Sopenharmony_ci        Instance(const SkMatrix& viewMatrix, const SkRRect& rrect, const SkRect& localRect,
116cb93a386Sopenharmony_ci                 const SkPMColor4f& color)
117cb93a386Sopenharmony_ci                : fViewMatrix(viewMatrix), fRRect(rrect), fLocalRect(localRect), fColor(color) {}
118cb93a386Sopenharmony_ci        SkMatrix fViewMatrix;
119cb93a386Sopenharmony_ci        SkRRect fRRect;
120cb93a386Sopenharmony_ci        SkRect fLocalRect;
121cb93a386Sopenharmony_ci        SkPMColor4f fColor;
122cb93a386Sopenharmony_ci        Instance* fNext = nullptr;
123cb93a386Sopenharmony_ci    };
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci    Instance* fHeadInstance;
126cb93a386Sopenharmony_ci    Instance** fTailInstance;
127cb93a386Sopenharmony_ci    int fInstanceCount = 1;
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci    sk_sp<const GrBuffer> fInstanceBuffer;
130cb93a386Sopenharmony_ci    sk_sp<const GrBuffer> fVertexBuffer;
131cb93a386Sopenharmony_ci    sk_sp<const GrBuffer> fIndexBuffer;
132cb93a386Sopenharmony_ci    int fBaseInstance = 0;
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    // If this op is prePrepared the created programInfo will be stored here for use in
135cb93a386Sopenharmony_ci    // onExecute. In the prePrepared case it will have been stored in the record-time arena.
136cb93a386Sopenharmony_ci    GrProgramInfo* fProgramInfo = nullptr;
137cb93a386Sopenharmony_ci};
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ciGR_MAKE_BITFIELD_CLASS_OPS(FillRRectOpImpl::ProcessorFlags)
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci// Hardware derivatives are not always accurate enough for highly elliptical corners. This method
142cb93a386Sopenharmony_ci// checks to make sure the corners will still all look good if we use HW derivatives.
143cb93a386Sopenharmony_cibool can_use_hw_derivatives_with_coverage(const GrShaderCaps&,
144cb93a386Sopenharmony_ci                                          const SkMatrix&,
145cb93a386Sopenharmony_ci                                          const SkRRect&);
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ciGrOp::Owner FillRRectOpImpl::Make(GrRecordingContext* ctx,
148cb93a386Sopenharmony_ci                                  SkArenaAlloc* arena,
149cb93a386Sopenharmony_ci                                  GrPaint&& paint,
150cb93a386Sopenharmony_ci                                  const SkMatrix& viewMatrix,
151cb93a386Sopenharmony_ci                                  const SkRRect& rrect,
152cb93a386Sopenharmony_ci                                  const SkRect& localRect,
153cb93a386Sopenharmony_ci                                  GrAA aa) {
154cb93a386Sopenharmony_ci    const GrCaps* caps = ctx->priv().caps();
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    if (!caps->drawInstancedSupport()) {
157cb93a386Sopenharmony_ci        return nullptr;
158cb93a386Sopenharmony_ci    }
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci    // We transform into a normalized -1..+1 space to draw the round rect. If the boundaries are too
161cb93a386Sopenharmony_ci    // large, the math can overflow. The caller can fall back on path rendering if this is the case.
162cb93a386Sopenharmony_ci    if (std::max(rrect.height(), rrect.width()) >= 1e6f) {
163cb93a386Sopenharmony_ci        return nullptr;
164cb93a386Sopenharmony_ci    }
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci    ProcessorFlags flags = ProcessorFlags::kNone;
167cb93a386Sopenharmony_ci    // TODO: Support perspective in a follow-on CL. This shouldn't be difficult, since we already
168cb93a386Sopenharmony_ci    // use HW derivatives. The only trick will be adjusting the AA outset to account for
169cb93a386Sopenharmony_ci    // perspective. (i.e., outset = 0.5 * z.)
170cb93a386Sopenharmony_ci    if (viewMatrix.hasPerspective()) {
171cb93a386Sopenharmony_ci        return nullptr;
172cb93a386Sopenharmony_ci    }
173cb93a386Sopenharmony_ci    if (can_use_hw_derivatives_with_coverage(*caps->shaderCaps(), viewMatrix, rrect)) {
174cb93a386Sopenharmony_ci        // HW derivatives (more specifically, fwidth()) are consistently faster on all platforms in
175cb93a386Sopenharmony_ci        // coverage mode. We use them as long as the approximation will be accurate enough.
176cb93a386Sopenharmony_ci        flags |= ProcessorFlags::kUseHWDerivatives;
177cb93a386Sopenharmony_ci    }
178cb93a386Sopenharmony_ci    if (aa == GrAA::kNo) {
179cb93a386Sopenharmony_ci        flags |= ProcessorFlags::kFakeNonAA;
180cb93a386Sopenharmony_ci    }
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci    return Helper::FactoryHelper<FillRRectOpImpl>(ctx, std::move(paint), arena, viewMatrix, rrect,
183cb93a386Sopenharmony_ci                                                  localRect, flags);
184cb93a386Sopenharmony_ci}
185cb93a386Sopenharmony_ci
186cb93a386Sopenharmony_ciFillRRectOpImpl::FillRRectOpImpl(GrProcessorSet* processorSet,
187cb93a386Sopenharmony_ci                                 const SkPMColor4f& paintColor,
188cb93a386Sopenharmony_ci                                 SkArenaAlloc* arena,
189cb93a386Sopenharmony_ci                                 const SkMatrix& viewMatrix,
190cb93a386Sopenharmony_ci                                 const SkRRect& rrect,
191cb93a386Sopenharmony_ci                                 const SkRect& localRect,
192cb93a386Sopenharmony_ci                                 ProcessorFlags processorFlags)
193cb93a386Sopenharmony_ci        : GrMeshDrawOp(ClassID())
194cb93a386Sopenharmony_ci        , fHelper(processorSet,
195cb93a386Sopenharmony_ci                  (processorFlags & ProcessorFlags::kFakeNonAA)
196cb93a386Sopenharmony_ci                          ? GrAAType::kNone
197cb93a386Sopenharmony_ci                          : GrAAType::kCoverage)  // Use analytic AA even if the RT is MSAA.
198cb93a386Sopenharmony_ci        , fProcessorFlags(processorFlags & ~(ProcessorFlags::kHasLocalCoords |
199cb93a386Sopenharmony_ci                                             ProcessorFlags::kWideColor |
200cb93a386Sopenharmony_ci                                             ProcessorFlags::kMSAAEnabled))
201cb93a386Sopenharmony_ci        , fHeadInstance(arena->make<Instance>(viewMatrix, rrect, localRect, paintColor))
202cb93a386Sopenharmony_ci        , fTailInstance(&fHeadInstance->fNext) {
203cb93a386Sopenharmony_ci    // FillRRectOp::Make fails if there is perspective.
204cb93a386Sopenharmony_ci    SkASSERT(!viewMatrix.hasPerspective());
205cb93a386Sopenharmony_ci    this->setBounds(viewMatrix.mapRect(rrect.getBounds()),
206cb93a386Sopenharmony_ci                    GrOp::HasAABloat(!(processorFlags & ProcessorFlags::kFakeNonAA)),
207cb93a386Sopenharmony_ci                    GrOp::IsHairline::kNo);
208cb93a386Sopenharmony_ci}
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_ciGrDrawOp::ClipResult FillRRectOpImpl::clipToShape(skgpu::v1::SurfaceDrawContext* sdc,
211cb93a386Sopenharmony_ci                                                  SkClipOp clipOp,
212cb93a386Sopenharmony_ci                                                  const SkMatrix& clipMatrix,
213cb93a386Sopenharmony_ci                                                  const GrShape& shape,
214cb93a386Sopenharmony_ci                                                  GrAA aa) {
215cb93a386Sopenharmony_ci    SkASSERT(fInstanceCount == 1);  // This needs to be called before combining.
216cb93a386Sopenharmony_ci    SkASSERT(fHeadInstance->fNext == nullptr);
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci    if ((shape.isRect() || shape.isRRect()) &&
219cb93a386Sopenharmony_ci        clipOp == SkClipOp::kIntersect &&
220cb93a386Sopenharmony_ci        (aa == GrAA::kNo) == (fProcessorFlags & ProcessorFlags::kFakeNonAA)) {
221cb93a386Sopenharmony_ci        // The clip shape is a round rect. Attempt to map it to a round rect in "viewMatrix" space.
222cb93a386Sopenharmony_ci        SkRRect clipRRect;
223cb93a386Sopenharmony_ci        if (clipMatrix == fHeadInstance->fViewMatrix) {
224cb93a386Sopenharmony_ci            if (shape.isRect()) {
225cb93a386Sopenharmony_ci                clipRRect.setRect(shape.rect());
226cb93a386Sopenharmony_ci            } else {
227cb93a386Sopenharmony_ci                clipRRect = shape.rrect();
228cb93a386Sopenharmony_ci            }
229cb93a386Sopenharmony_ci        } else {
230cb93a386Sopenharmony_ci            // Find a matrix that maps from "clipMatrix" space to "viewMatrix" space.
231cb93a386Sopenharmony_ci            SkASSERT(!fHeadInstance->fViewMatrix.hasPerspective());
232cb93a386Sopenharmony_ci            if (clipMatrix.hasPerspective()) {
233cb93a386Sopenharmony_ci                return ClipResult::kFail;
234cb93a386Sopenharmony_ci            }
235cb93a386Sopenharmony_ci            SkMatrix clipToView;
236cb93a386Sopenharmony_ci            if (!fHeadInstance->fViewMatrix.invert(&clipToView)) {
237cb93a386Sopenharmony_ci                return ClipResult::kClippedOut;
238cb93a386Sopenharmony_ci            }
239cb93a386Sopenharmony_ci            clipToView.preConcat(clipMatrix);
240cb93a386Sopenharmony_ci            SkASSERT(!clipToView.hasPerspective());
241cb93a386Sopenharmony_ci            if (!SkScalarNearlyZero(clipToView.getSkewX()) ||
242cb93a386Sopenharmony_ci                !SkScalarNearlyZero(clipToView.getSkewY())) {
243cb93a386Sopenharmony_ci                // A rect in "clipMatrix" space is not a rect in "viewMatrix" space.
244cb93a386Sopenharmony_ci                return ClipResult::kFail;
245cb93a386Sopenharmony_ci            }
246cb93a386Sopenharmony_ci            clipToView.setSkewX(0);
247cb93a386Sopenharmony_ci            clipToView.setSkewY(0);
248cb93a386Sopenharmony_ci            SkASSERT(clipToView.rectStaysRect());
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_ci            if (shape.isRect()) {
251cb93a386Sopenharmony_ci                clipRRect.setRect(clipToView.mapRect(shape.rect()));
252cb93a386Sopenharmony_ci            } else {
253cb93a386Sopenharmony_ci                if (!shape.rrect().transform(clipToView, &clipRRect)) {
254cb93a386Sopenharmony_ci                    // Transforming the rrect failed. This shouldn't generally happen except in
255cb93a386Sopenharmony_ci                    // cases of fp32 overflow.
256cb93a386Sopenharmony_ci                    return ClipResult::kFail;
257cb93a386Sopenharmony_ci                }
258cb93a386Sopenharmony_ci            }
259cb93a386Sopenharmony_ci        }
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_ci        // Intersect our round rect with the clip shape.
262cb93a386Sopenharmony_ci        SkRRect isectRRect;
263cb93a386Sopenharmony_ci        if (fHeadInstance->fRRect.isRect() && clipRRect.isRect()) {
264cb93a386Sopenharmony_ci            SkRect isectRect;
265cb93a386Sopenharmony_ci            if (!isectRect.intersect(fHeadInstance->fRRect.rect(), clipRRect.rect())) {
266cb93a386Sopenharmony_ci                return ClipResult::kClippedOut;
267cb93a386Sopenharmony_ci            }
268cb93a386Sopenharmony_ci            isectRRect.setRect(isectRect);
269cb93a386Sopenharmony_ci        } else {
270cb93a386Sopenharmony_ci            isectRRect = SkRRectPriv::ConservativeIntersect(fHeadInstance->fRRect, clipRRect);
271cb93a386Sopenharmony_ci            if (isectRRect.isEmpty()) {
272cb93a386Sopenharmony_ci                // The round rects did not intersect at all or the intersection was too complicated
273cb93a386Sopenharmony_ci                // to compute quickly.
274cb93a386Sopenharmony_ci                return ClipResult::kFail;
275cb93a386Sopenharmony_ci            }
276cb93a386Sopenharmony_ci        }
277cb93a386Sopenharmony_ci
278cb93a386Sopenharmony_ci        // Don't apply the clip geometrically if it becomes subpixel, since then the hairline
279cb93a386Sopenharmony_ci        // rendering may outset beyond the original clip.
280cb93a386Sopenharmony_ci        SkRect devISectBounds = fHeadInstance->fViewMatrix.mapRect(isectRRect.rect());
281cb93a386Sopenharmony_ci        if (devISectBounds.width() < 1.f || devISectBounds.height() < 1.f) {
282cb93a386Sopenharmony_ci            return ClipResult::kFail;
283cb93a386Sopenharmony_ci        }
284cb93a386Sopenharmony_ci
285cb93a386Sopenharmony_ci        // Update the local rect.
286cb93a386Sopenharmony_ci        auto rect = skvx::bit_pun<grvx::float4>(fHeadInstance->fRRect.rect());
287cb93a386Sopenharmony_ci        auto local = skvx::bit_pun<grvx::float4>(fHeadInstance->fLocalRect);
288cb93a386Sopenharmony_ci        auto isect = skvx::bit_pun<grvx::float4>(isectRRect.rect());
289cb93a386Sopenharmony_ci        auto rectToLocalSize = (local - skvx::shuffle<2,3,0,1>(local)) /
290cb93a386Sopenharmony_ci                               (rect - skvx::shuffle<2,3,0,1>(rect));
291cb93a386Sopenharmony_ci        fHeadInstance->fLocalRect = skvx::bit_pun<SkRect>((isect - rect) * rectToLocalSize + local);
292cb93a386Sopenharmony_ci
293cb93a386Sopenharmony_ci        // Update the round rect.
294cb93a386Sopenharmony_ci        fHeadInstance->fRRect = isectRRect;
295cb93a386Sopenharmony_ci        return ClipResult::kClippedGeometrically;
296cb93a386Sopenharmony_ci    }
297cb93a386Sopenharmony_ci
298cb93a386Sopenharmony_ci    return ClipResult::kFail;
299cb93a386Sopenharmony_ci}
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ciGrProcessorSet::Analysis FillRRectOpImpl::finalize(const GrCaps& caps, const GrAppliedClip* clip,
302cb93a386Sopenharmony_ci                                                   GrClampType clampType) {
303cb93a386Sopenharmony_ci    SkASSERT(fInstanceCount == 1);
304cb93a386Sopenharmony_ci    SkASSERT(fHeadInstance->fNext == nullptr);
305cb93a386Sopenharmony_ci
306cb93a386Sopenharmony_ci    bool isWideColor;
307cb93a386Sopenharmony_ci    auto analysis = fHelper.finalizeProcessors(caps, clip, clampType,
308cb93a386Sopenharmony_ci                                               GrProcessorAnalysisCoverage::kSingleChannel,
309cb93a386Sopenharmony_ci                                               &fHeadInstance->fColor, &isWideColor);
310cb93a386Sopenharmony_ci    if (isWideColor) {
311cb93a386Sopenharmony_ci        fProcessorFlags |= ProcessorFlags::kWideColor;
312cb93a386Sopenharmony_ci    }
313cb93a386Sopenharmony_ci    if (analysis.usesLocalCoords()) {
314cb93a386Sopenharmony_ci        fProcessorFlags |= ProcessorFlags::kHasLocalCoords;
315cb93a386Sopenharmony_ci    }
316cb93a386Sopenharmony_ci    return analysis;
317cb93a386Sopenharmony_ci}
318cb93a386Sopenharmony_ci
319cb93a386Sopenharmony_ciGrOp::CombineResult FillRRectOpImpl::onCombineIfPossible(GrOp* op,
320cb93a386Sopenharmony_ci                                                         SkArenaAlloc*,
321cb93a386Sopenharmony_ci                                                         const GrCaps& caps) {
322cb93a386Sopenharmony_ci    auto that = op->cast<FillRRectOpImpl>();
323cb93a386Sopenharmony_ci    if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds()) ||
324cb93a386Sopenharmony_ci        fProcessorFlags != that->fProcessorFlags) {
325cb93a386Sopenharmony_ci        return CombineResult::kCannotCombine;
326cb93a386Sopenharmony_ci    }
327cb93a386Sopenharmony_ci
328cb93a386Sopenharmony_ci    *fTailInstance = that->fHeadInstance;
329cb93a386Sopenharmony_ci    fTailInstance = that->fTailInstance;
330cb93a386Sopenharmony_ci    fInstanceCount += that->fInstanceCount;
331cb93a386Sopenharmony_ci    return CombineResult::kMerged;
332cb93a386Sopenharmony_ci}
333cb93a386Sopenharmony_ci
334cb93a386Sopenharmony_ciclass FillRRectOpImpl::Processor final : public GrGeometryProcessor {
335cb93a386Sopenharmony_cipublic:
336cb93a386Sopenharmony_ci    static GrGeometryProcessor* Make(SkArenaAlloc* arena, GrAAType aaType, ProcessorFlags flags) {
337cb93a386Sopenharmony_ci        return arena->make([&](void* ptr) {
338cb93a386Sopenharmony_ci            return new (ptr) Processor(aaType, flags);
339cb93a386Sopenharmony_ci        });
340cb93a386Sopenharmony_ci    }
341cb93a386Sopenharmony_ci
342cb93a386Sopenharmony_ci    const char* name() const override { return "FillRRectOp::Processor"; }
343cb93a386Sopenharmony_ci
344cb93a386Sopenharmony_ci    SkString getShaderDfxInfo() const override {
345cb93a386Sopenharmony_ci        SkString format;
346cb93a386Sopenharmony_ci        format.printf("ShaderDfx_FillRRectOp_%d", fFlags);
347cb93a386Sopenharmony_ci        return format;
348cb93a386Sopenharmony_ci    }
349cb93a386Sopenharmony_ci
350cb93a386Sopenharmony_ci    void addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
351cb93a386Sopenharmony_ci        b->addBits(kNumProcessorFlags, (uint32_t)fFlags,  "flags");
352cb93a386Sopenharmony_ci    }
353cb93a386Sopenharmony_ci
354cb93a386Sopenharmony_ci    std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override;
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ciprivate:
357cb93a386Sopenharmony_ci    class Impl;
358cb93a386Sopenharmony_ci
359cb93a386Sopenharmony_ci    Processor(GrAAType aaType, ProcessorFlags flags)
360cb93a386Sopenharmony_ci            : GrGeometryProcessor(kGrFillRRectOp_Processor_ClassID)
361cb93a386Sopenharmony_ci            , fFlags(flags) {
362cb93a386Sopenharmony_ci        this->setVertexAttributes(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
363cb93a386Sopenharmony_ci
364cb93a386Sopenharmony_ci        fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
365cb93a386Sopenharmony_ci        fInstanceAttribs.emplace_back("translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
366cb93a386Sopenharmony_ci        fInstanceAttribs.emplace_back("radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
367cb93a386Sopenharmony_ci        fInstanceAttribs.emplace_back("radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
368cb93a386Sopenharmony_ci        fColorAttrib = &fInstanceAttribs.push_back(
369cb93a386Sopenharmony_ci                MakeColorAttribute("color", (fFlags & ProcessorFlags::kWideColor)));
370cb93a386Sopenharmony_ci        if (fFlags & ProcessorFlags::kHasLocalCoords) {
371cb93a386Sopenharmony_ci            fInstanceAttribs.emplace_back(
372cb93a386Sopenharmony_ci                    "local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
373cb93a386Sopenharmony_ci        }
374cb93a386Sopenharmony_ci        SkASSERT(fInstanceAttribs.count() <= kMaxInstanceAttribs);
375cb93a386Sopenharmony_ci        this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
376cb93a386Sopenharmony_ci    }
377cb93a386Sopenharmony_ci
378cb93a386Sopenharmony_ci    inline static constexpr Attribute kVertexAttribs[] = {
379cb93a386Sopenharmony_ci            {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
380cb93a386Sopenharmony_ci            {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
381cb93a386Sopenharmony_ci            // Coverage only.
382cb93a386Sopenharmony_ci            {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
383cb93a386Sopenharmony_ci
384cb93a386Sopenharmony_ci    const ProcessorFlags fFlags;
385cb93a386Sopenharmony_ci
386cb93a386Sopenharmony_ci    constexpr static int kMaxInstanceAttribs = 6;
387cb93a386Sopenharmony_ci    SkSTArray<kMaxInstanceAttribs, Attribute> fInstanceAttribs;
388cb93a386Sopenharmony_ci    const Attribute* fColorAttrib;
389cb93a386Sopenharmony_ci};
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_ci// Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear
392cb93a386Sopenharmony_ci// coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
393cb93a386Sopenharmony_ci// edges. The Vertex struct tells the shader where to place its vertex within a normalized
394cb93a386Sopenharmony_ci// ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode.
395cb93a386Sopenharmony_cistruct CoverageVertex {
396cb93a386Sopenharmony_ci    std::array<float, 4> fRadiiSelector;
397cb93a386Sopenharmony_ci    std::array<float, 2> fCorner;
398cb93a386Sopenharmony_ci    std::array<float, 2> fRadiusOutset;
399cb93a386Sopenharmony_ci    std::array<float, 2> fAABloatDirection;
400cb93a386Sopenharmony_ci    float fCoverage;
401cb93a386Sopenharmony_ci    float fIsLinearCoverage;
402cb93a386Sopenharmony_ci};
403cb93a386Sopenharmony_ci
404cb93a386Sopenharmony_ci// This is the offset (when multiplied by radii) from the corners of a bounding box to the vertices
405cb93a386Sopenharmony_ci// of its inscribed octagon. We draw the outside portion of arcs with quarter-octagons rather than
406cb93a386Sopenharmony_ci// rectangles.
407cb93a386Sopenharmony_cistatic constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2);
408cb93a386Sopenharmony_ci
409cb93a386Sopenharmony_cistatic constexpr CoverageVertex kVertexData[] = {
410cb93a386Sopenharmony_ci        // Left inset edge.
411cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{0,-1}},  {{+1,0}},  1,  1},
412cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{0,+1}},  {{+1,0}},  1,  1},
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ci        // Top inset edge.
415cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{+1,0}},  {{0,+1}},  1,  1},
416cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{-1,0}},  {{0,+1}},  1,  1},
417cb93a386Sopenharmony_ci
418cb93a386Sopenharmony_ci        // Right inset edge.
419cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{0,+1}},  {{-1,0}},  1,  1},
420cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{0,-1}},  {{-1,0}},  1,  1},
421cb93a386Sopenharmony_ci
422cb93a386Sopenharmony_ci        // Bottom inset edge.
423cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{-1,0}},  {{0,-1}},  1,  1},
424cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{+1,0}},  {{0,-1}},  1,  1},
425cb93a386Sopenharmony_ci
426cb93a386Sopenharmony_ci
427cb93a386Sopenharmony_ci        // Left outset edge.
428cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{0,-1}},  {{-1,0}},  0,  1},
429cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{0,+1}},  {{-1,0}},  0,  1},
430cb93a386Sopenharmony_ci
431cb93a386Sopenharmony_ci        // Top outset edge.
432cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{+1,0}},  {{0,-1}},  0,  1},
433cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{-1,0}},  {{0,-1}},  0,  1},
434cb93a386Sopenharmony_ci
435cb93a386Sopenharmony_ci        // Right outset edge.
436cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{0,+1}},  {{+1,0}},  0,  1},
437cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{0,-1}},  {{+1,0}},  0,  1},
438cb93a386Sopenharmony_ci
439cb93a386Sopenharmony_ci        // Bottom outset edge.
440cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{-1,0}},  {{0,+1}},  0,  1},
441cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{+1,0}},  {{0,+1}},  0,  1},
442cb93a386Sopenharmony_ci
443cb93a386Sopenharmony_ci
444cb93a386Sopenharmony_ci        // Top-left corner.
445cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{ 0,+1}},  {{-1, 0}},  0,  0},
446cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{ 0,+1}},  {{+1, 0}},  1,  0},
447cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{+1, 0}},  {{ 0,+1}},  1,  0},
448cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{+1, 0}},  {{ 0,-1}},  0,  0},
449cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{+kOctoOffset,0}},  {{-1,-1}},  0,  0},
450cb93a386Sopenharmony_ci        {{{1,0,0,0}},  {{-1,-1}},  {{0,+kOctoOffset}},  {{-1,-1}},  0,  0},
451cb93a386Sopenharmony_ci
452cb93a386Sopenharmony_ci        // Top-right corner.
453cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{-1, 0}},  {{ 0,-1}},  0,  0},
454cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{-1, 0}},  {{ 0,+1}},  1,  0},
455cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{ 0,+1}},  {{-1, 0}},  1,  0},
456cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{ 0,+1}},  {{+1, 0}},  0,  0},
457cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{0,+kOctoOffset}},  {{+1,-1}},  0,  0},
458cb93a386Sopenharmony_ci        {{{0,1,0,0}},  {{+1,-1}},  {{-kOctoOffset,0}},  {{+1,-1}},  0,  0},
459cb93a386Sopenharmony_ci
460cb93a386Sopenharmony_ci        // Bottom-right corner.
461cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{ 0,-1}},  {{+1, 0}},  0,  0},
462cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{ 0,-1}},  {{-1, 0}},  1,  0},
463cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{-1, 0}},  {{ 0,-1}},  1,  0},
464cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{-1, 0}},  {{ 0,+1}},  0,  0},
465cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{-kOctoOffset,0}},  {{+1,+1}},  0,  0},
466cb93a386Sopenharmony_ci        {{{0,0,1,0}},  {{+1,+1}},  {{0,-kOctoOffset}},  {{+1,+1}},  0,  0},
467cb93a386Sopenharmony_ci
468cb93a386Sopenharmony_ci        // Bottom-left corner.
469cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{+1, 0}},  {{ 0,+1}},  0,  0},
470cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{+1, 0}},  {{ 0,-1}},  1,  0},
471cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{ 0,-1}},  {{+1, 0}},  1,  0},
472cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{ 0,-1}},  {{-1, 0}},  0,  0},
473cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{0,-kOctoOffset}},  {{-1,+1}},  0,  0},
474cb93a386Sopenharmony_ci        {{{0,0,0,1}},  {{-1,+1}},  {{+kOctoOffset,0}},  {{-1,+1}},  0,  0}};
475cb93a386Sopenharmony_ci
476cb93a386Sopenharmony_ciGR_DECLARE_STATIC_UNIQUE_KEY(gVertexBufferKey);
477cb93a386Sopenharmony_ci
478cb93a386Sopenharmony_cistatic constexpr uint16_t kIndexData[] = {
479cb93a386Sopenharmony_ci        // Inset octagon (solid coverage).
480cb93a386Sopenharmony_ci        0, 1, 7,
481cb93a386Sopenharmony_ci        1, 2, 7,
482cb93a386Sopenharmony_ci        7, 2, 6,
483cb93a386Sopenharmony_ci        2, 3, 6,
484cb93a386Sopenharmony_ci        6, 3, 5,
485cb93a386Sopenharmony_ci        3, 4, 5,
486cb93a386Sopenharmony_ci
487cb93a386Sopenharmony_ci        // AA borders (linear coverage).
488cb93a386Sopenharmony_ci        0, 1, 8, 1, 9, 8,
489cb93a386Sopenharmony_ci        2, 3, 10, 3, 11, 10,
490cb93a386Sopenharmony_ci        4, 5, 12, 5, 13, 12,
491cb93a386Sopenharmony_ci        6, 7, 14, 7, 15, 14,
492cb93a386Sopenharmony_ci
493cb93a386Sopenharmony_ci        // Top-left arc.
494cb93a386Sopenharmony_ci        16, 17, 21,
495cb93a386Sopenharmony_ci        17, 21, 18,
496cb93a386Sopenharmony_ci        21, 18, 20,
497cb93a386Sopenharmony_ci        18, 20, 19,
498cb93a386Sopenharmony_ci
499cb93a386Sopenharmony_ci        // Top-right arc.
500cb93a386Sopenharmony_ci        22, 23, 27,
501cb93a386Sopenharmony_ci        23, 27, 24,
502cb93a386Sopenharmony_ci        27, 24, 26,
503cb93a386Sopenharmony_ci        24, 26, 25,
504cb93a386Sopenharmony_ci
505cb93a386Sopenharmony_ci        // Bottom-right arc.
506cb93a386Sopenharmony_ci        28, 29, 33,
507cb93a386Sopenharmony_ci        29, 33, 30,
508cb93a386Sopenharmony_ci        33, 30, 32,
509cb93a386Sopenharmony_ci        30, 32, 31,
510cb93a386Sopenharmony_ci
511cb93a386Sopenharmony_ci        // Bottom-left arc.
512cb93a386Sopenharmony_ci        34, 35, 39,
513cb93a386Sopenharmony_ci        35, 39, 36,
514cb93a386Sopenharmony_ci        39, 36, 38,
515cb93a386Sopenharmony_ci        36, 38, 37};
516cb93a386Sopenharmony_ci
517cb93a386Sopenharmony_ciGR_DECLARE_STATIC_UNIQUE_KEY(gIndexBufferKey);
518cb93a386Sopenharmony_ci
519cb93a386Sopenharmony_civoid FillRRectOpImpl::onPrepareDraws(GrMeshDrawTarget* target) {
520cb93a386Sopenharmony_ci    if (!fProgramInfo) {
521cb93a386Sopenharmony_ci        this->createProgramInfo(target);
522cb93a386Sopenharmony_ci    }
523cb93a386Sopenharmony_ci
524cb93a386Sopenharmony_ci    size_t instanceStride = fProgramInfo->geomProc().instanceStride();
525cb93a386Sopenharmony_ci
526cb93a386Sopenharmony_ci    if (VertexWriter instanceWrter = target->makeVertexSpace(instanceStride, fInstanceCount,
527cb93a386Sopenharmony_ci                                                             &fInstanceBuffer, &fBaseInstance)) {
528cb93a386Sopenharmony_ci        SkDEBUGCODE(auto end = instanceWrter.makeOffset(instanceStride * fInstanceCount));
529cb93a386Sopenharmony_ci        for (Instance* i = fHeadInstance; i; i = i->fNext) {
530cb93a386Sopenharmony_ci            auto [l, t, r, b] = i->fRRect.rect();
531cb93a386Sopenharmony_ci
532cb93a386Sopenharmony_ci            // Produce a matrix that draws the round rect from normalized [-1, -1, +1, +1] space.
533cb93a386Sopenharmony_ci            SkMatrix m;
534cb93a386Sopenharmony_ci            // Unmap the normalized rect [-1, -1, +1, +1] back to [l, t, r, b].
535cb93a386Sopenharmony_ci            m.setScaleTranslate((r - l)/2, (b - t)/2, (l + r)/2, (t + b)/2);
536cb93a386Sopenharmony_ci            // Map to device space.
537cb93a386Sopenharmony_ci            m.postConcat(i->fViewMatrix);
538cb93a386Sopenharmony_ci
539cb93a386Sopenharmony_ci            // Convert the radii to [-1, -1, +1, +1] space and write their attribs.
540cb93a386Sopenharmony_ci            grvx::float4 radiiX, radiiY;
541cb93a386Sopenharmony_ci            skvx::strided_load2(&SkRRectPriv::GetRadiiArray(i->fRRect)->fX, radiiX, radiiY);
542cb93a386Sopenharmony_ci            radiiX *= 2 / (r - l);
543cb93a386Sopenharmony_ci            radiiY *= 2 / (b - t);
544cb93a386Sopenharmony_ci
545cb93a386Sopenharmony_ci            instanceWrter << m.getScaleX() << m.getSkewX() << m.getSkewY() << m.getScaleY()
546cb93a386Sopenharmony_ci                          << m.getTranslateX() << m.getTranslateY()
547cb93a386Sopenharmony_ci                          << radiiX << radiiY
548cb93a386Sopenharmony_ci                          << GrVertexColor(i->fColor, fProcessorFlags & ProcessorFlags::kWideColor)
549cb93a386Sopenharmony_ci                          << VertexWriter::If(fProcessorFlags & ProcessorFlags::kHasLocalCoords,
550cb93a386Sopenharmony_ci                                              i->fLocalRect);
551cb93a386Sopenharmony_ci        }
552cb93a386Sopenharmony_ci        SkASSERT(instanceWrter == end);
553cb93a386Sopenharmony_ci    }
554cb93a386Sopenharmony_ci
555cb93a386Sopenharmony_ci    GR_DEFINE_STATIC_UNIQUE_KEY(gIndexBufferKey);
556cb93a386Sopenharmony_ci
557cb93a386Sopenharmony_ci    fIndexBuffer = target->resourceProvider()->findOrMakeStaticBuffer(GrGpuBufferType::kIndex,
558cb93a386Sopenharmony_ci                                                                      sizeof(kIndexData),
559cb93a386Sopenharmony_ci                                                                      kIndexData, gIndexBufferKey);
560cb93a386Sopenharmony_ci
561cb93a386Sopenharmony_ci    GR_DEFINE_STATIC_UNIQUE_KEY(gVertexBufferKey);
562cb93a386Sopenharmony_ci
563cb93a386Sopenharmony_ci    fVertexBuffer = target->resourceProvider()->findOrMakeStaticBuffer(GrGpuBufferType::kVertex,
564cb93a386Sopenharmony_ci                                                                      sizeof(kVertexData),
565cb93a386Sopenharmony_ci                                                                      kVertexData,
566cb93a386Sopenharmony_ci                                                                      gVertexBufferKey);
567cb93a386Sopenharmony_ci}
568cb93a386Sopenharmony_ci
569cb93a386Sopenharmony_ciclass FillRRectOpImpl::Processor::Impl : public ProgramImpl {
570cb93a386Sopenharmony_cipublic:
571cb93a386Sopenharmony_ci    void setData(const GrGLSLProgramDataManager&,
572cb93a386Sopenharmony_ci                 const GrShaderCaps&,
573cb93a386Sopenharmony_ci                 const GrGeometryProcessor&) override {}
574cb93a386Sopenharmony_ci
575cb93a386Sopenharmony_ciprivate:
576cb93a386Sopenharmony_ci    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
577cb93a386Sopenharmony_ci        GrGLSLVertexBuilder* v = args.fVertBuilder;
578cb93a386Sopenharmony_ci        GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
579cb93a386Sopenharmony_ci
580cb93a386Sopenharmony_ci        const auto& proc = args.fGeomProc.cast<Processor>();
581cb93a386Sopenharmony_ci        bool useHWDerivatives = (proc.fFlags & ProcessorFlags::kUseHWDerivatives);
582cb93a386Sopenharmony_ci
583cb93a386Sopenharmony_ci        SkASSERT(proc.vertexStride() == sizeof(CoverageVertex));
584cb93a386Sopenharmony_ci
585cb93a386Sopenharmony_ci        GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
586cb93a386Sopenharmony_ci        varyings->emitAttributes(proc);
587cb93a386Sopenharmony_ci        f->codeAppendf("half4 %s;", args.fOutputColor);
588cb93a386Sopenharmony_ci        varyings->addPassThroughAttribute(proc.fColorAttrib->asShaderVar(),
589cb93a386Sopenharmony_ci                                          args.fOutputColor,
590cb93a386Sopenharmony_ci                                          GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
591cb93a386Sopenharmony_ci
592cb93a386Sopenharmony_ci        // Emit the vertex shader.
593cb93a386Sopenharmony_ci        // When MSAA is enabled, we need to make sure every sample gets lit up on pixels that have
594cb93a386Sopenharmony_ci        // fractional coverage. We do this by making the ramp wider.
595cb93a386Sopenharmony_ci        v->codeAppendf("float aa_bloat_multiplier = %i;",
596cb93a386Sopenharmony_ci                       (proc.fFlags & ProcessorFlags::kMSAAEnabled)
597cb93a386Sopenharmony_ci                               ? 2    // Outset an entire pixel (2 radii).
598cb93a386Sopenharmony_ci                       : (!(proc.fFlags & ProcessorFlags::kFakeNonAA))
599cb93a386Sopenharmony_ci                               ? 1    // Outset one half pixel (1 radius).
600cb93a386Sopenharmony_ci                               : 0);  // No AA bloat.
601cb93a386Sopenharmony_ci
602cb93a386Sopenharmony_ci        // Unpack vertex attribs.
603cb93a386Sopenharmony_ci        v->codeAppend("float2 corner = corner_and_radius_outsets.xy;");
604cb93a386Sopenharmony_ci        v->codeAppend("float2 radius_outset = corner_and_radius_outsets.zw;");
605cb93a386Sopenharmony_ci        v->codeAppend("float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
606cb93a386Sopenharmony_ci        v->codeAppend("float is_linear_coverage = aa_bloat_and_coverage.w;");
607cb93a386Sopenharmony_ci
608cb93a386Sopenharmony_ci        // Find the amount to bloat each edge for AA (in source space).
609cb93a386Sopenharmony_ci        v->codeAppend("float2 pixellength = inversesqrt("
610cb93a386Sopenharmony_ci                              "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
611cb93a386Sopenharmony_ci        v->codeAppend("float4 normalized_axis_dirs = skew * pixellength.xyxy;");
612cb93a386Sopenharmony_ci        v->codeAppend("float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
613cb93a386Sopenharmony_ci                                           "abs(normalized_axis_dirs.zw));");
614cb93a386Sopenharmony_ci        v->codeAppend("float2 aa_bloatradius = axiswidths * pixellength * .5;");
615cb93a386Sopenharmony_ci
616cb93a386Sopenharmony_ci        // Identify our radii.
617cb93a386Sopenharmony_ci        v->codeAppend("float4 radii_and_neighbors = radii_selector"
618cb93a386Sopenharmony_ci                              "* float4x4(radii_x, radii_y, radii_x.yxwz, radii_y.wzyx);");
619cb93a386Sopenharmony_ci        v->codeAppend("float2 radii = radii_and_neighbors.xy;");
620cb93a386Sopenharmony_ci        v->codeAppend("float2 neighbor_radii = radii_and_neighbors.zw;");
621cb93a386Sopenharmony_ci
622cb93a386Sopenharmony_ci        v->codeAppend("float coverage_multiplier = 1;");
623cb93a386Sopenharmony_ci        v->codeAppend("if (any(greaterThan(aa_bloatradius, float2(1)))) {");
624cb93a386Sopenharmony_ci                          // The rrect is more narrow than a half-pixel AA coverage ramp. We can't
625cb93a386Sopenharmony_ci                          // draw as-is or else opposite AA borders will overlap. Instead, fudge the
626cb93a386Sopenharmony_ci                          // size up to the width of a coverage ramp, and then reduce total coverage
627cb93a386Sopenharmony_ci                          // to make the rect appear more thin.
628cb93a386Sopenharmony_ci        v->codeAppend(    "corner = max(abs(corner), aa_bloatradius) * sign(corner);");
629cb93a386Sopenharmony_ci        v->codeAppend(    "coverage_multiplier = 1 / (max(aa_bloatradius.x, 1) * "
630cb93a386Sopenharmony_ci                                                     "max(aa_bloatradius.y, 1));");
631cb93a386Sopenharmony_ci                          // Set radii to zero to ensure we take the "linear coverage" codepath.
632cb93a386Sopenharmony_ci                          // (The "coverage" variable only has effect in the linear codepath.)
633cb93a386Sopenharmony_ci        v->codeAppend(    "radii = float2(0);");
634cb93a386Sopenharmony_ci        v->codeAppend("}");
635cb93a386Sopenharmony_ci
636cb93a386Sopenharmony_ci        // Unpack coverage.
637cb93a386Sopenharmony_ci        v->codeAppend("float coverage = aa_bloat_and_coverage.z;");
638cb93a386Sopenharmony_ci        if (proc.fFlags & ProcessorFlags::kMSAAEnabled) {
639cb93a386Sopenharmony_ci            // MSAA has a wider ramp that goes from -.5 to 1.5 instead of 0 to 1.
640cb93a386Sopenharmony_ci            v->codeAppendf("coverage = (coverage - .5) * aa_bloat_multiplier + .5;");
641cb93a386Sopenharmony_ci        }
642cb93a386Sopenharmony_ci
643cb93a386Sopenharmony_ci        v->codeAppend("if (any(lessThan(radii, aa_bloatradius * 1.5))) {");
644cb93a386Sopenharmony_ci                          // The radii are very small. Demote this arc to a sharp 90 degree corner.
645cb93a386Sopenharmony_ci        v->codeAppend(    "radii = float2(0);");
646cb93a386Sopenharmony_ci                          // Convert to a standard picture frame for an AA rect instead of the round
647cb93a386Sopenharmony_ci                          // rect geometry.
648cb93a386Sopenharmony_ci        v->codeAppend(    "aa_bloat_direction = sign(corner);");
649cb93a386Sopenharmony_ci        v->codeAppend(    "if (coverage > .5) {");  // Are we an inset edge?
650cb93a386Sopenharmony_ci        v->codeAppend(        "aa_bloat_direction = -aa_bloat_direction;");
651cb93a386Sopenharmony_ci        v->codeAppend(    "}");
652cb93a386Sopenharmony_ci        v->codeAppend(    "is_linear_coverage = 1;");
653cb93a386Sopenharmony_ci        v->codeAppend("} else {");
654cb93a386Sopenharmony_ci                          // Don't let radii get smaller than a coverage ramp plus an extra half
655cb93a386Sopenharmony_ci                          // pixel for MSAA. Always use the same amount so we don't pop when
656cb93a386Sopenharmony_ci                          // switching between MSAA and coverage.
657cb93a386Sopenharmony_ci        v->codeAppend(    "radii = clamp(radii, pixellength * 1.5, 2 - pixellength * 1.5);");
658cb93a386Sopenharmony_ci        v->codeAppend(    "neighbor_radii = clamp(neighbor_radii, pixellength * 1.5, "
659cb93a386Sopenharmony_ci                                                 "2 - pixellength * 1.5);");
660cb93a386Sopenharmony_ci                          // Don't let neighboring radii get closer together than 1/16 pixel.
661cb93a386Sopenharmony_ci        v->codeAppend(    "float2 spacing = 2 - radii - neighbor_radii;");
662cb93a386Sopenharmony_ci        v->codeAppend(    "float2 extra_pad = max(pixellength * .0625 - spacing, float2(0));");
663cb93a386Sopenharmony_ci        v->codeAppend(    "radii -= extra_pad * .5;");
664cb93a386Sopenharmony_ci        v->codeAppend("}");
665cb93a386Sopenharmony_ci
666cb93a386Sopenharmony_ci        // Find our vertex position, adjusted for radii and bloated for AA. Our rect is drawn in
667cb93a386Sopenharmony_ci        // normalized [-1,-1,+1,+1] space.
668cb93a386Sopenharmony_ci        v->codeAppend("float2 aa_outset = "
669cb93a386Sopenharmony_ci                              "aa_bloat_direction * aa_bloatradius * aa_bloat_multiplier;");
670cb93a386Sopenharmony_ci        v->codeAppend("float2 vertexpos = corner + radius_outset * radii + aa_outset;");
671cb93a386Sopenharmony_ci
672cb93a386Sopenharmony_ci        v->codeAppend("if (coverage > .5) {");  // Are we an inset edge?
673cb93a386Sopenharmony_ci                          // Don't allow the aa insets to overlap. i.e., Don't let them inset past
674cb93a386Sopenharmony_ci                          // the center (x=y=0). Since we don't allow the rect to become thinner
675cb93a386Sopenharmony_ci                          // than 1px, this should only happen when using MSAA, where we inset by an
676cb93a386Sopenharmony_ci                          // entire pixel instead of half.
677cb93a386Sopenharmony_ci        v->codeAppend(    "if (aa_bloat_direction.x != 0 && vertexpos.x * corner.x < 0) {");
678cb93a386Sopenharmony_ci        v->codeAppend(        "float backset = abs(vertexpos.x);");
679cb93a386Sopenharmony_ci        v->codeAppend(        "vertexpos.x = 0;");
680cb93a386Sopenharmony_ci        v->codeAppend(        "vertexpos.y += "
681cb93a386Sopenharmony_ci                                      "backset * sign(corner.y) * pixellength.y/pixellength.x;");
682cb93a386Sopenharmony_ci        v->codeAppend(        "coverage = (coverage - .5) * abs(corner.x) / "
683cb93a386Sopenharmony_ci                                      "(abs(corner.x) + backset) + .5;");
684cb93a386Sopenharmony_ci        v->codeAppend(    "}");
685cb93a386Sopenharmony_ci        v->codeAppend(    "if (aa_bloat_direction.y != 0 && vertexpos.y * corner.y < 0) {");
686cb93a386Sopenharmony_ci        v->codeAppend(        "float backset = abs(vertexpos.y);");
687cb93a386Sopenharmony_ci        v->codeAppend(        "vertexpos.y = 0;");
688cb93a386Sopenharmony_ci        v->codeAppend(        "vertexpos.x += "
689cb93a386Sopenharmony_ci                                      "backset * sign(corner.x) * pixellength.x/pixellength.y;");
690cb93a386Sopenharmony_ci        v->codeAppend(        "coverage = (coverage - .5) * abs(corner.y) / "
691cb93a386Sopenharmony_ci                                      "(abs(corner.y) + backset) + .5;");
692cb93a386Sopenharmony_ci        v->codeAppend(    "}");
693cb93a386Sopenharmony_ci        v->codeAppend("}");
694cb93a386Sopenharmony_ci
695cb93a386Sopenharmony_ci        // Write positions
696cb93a386Sopenharmony_ci        GrShaderVar localCoord("", kFloat2_GrSLType);
697cb93a386Sopenharmony_ci        if (proc.fFlags & ProcessorFlags::kHasLocalCoords) {
698cb93a386Sopenharmony_ci            v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
699cb93a386Sopenharmony_ci                                               "local_rect.zw * (1 + vertexpos)) * .5;");
700cb93a386Sopenharmony_ci            gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
701cb93a386Sopenharmony_ci        }
702cb93a386Sopenharmony_ci
703cb93a386Sopenharmony_ci        // Transform to device space.
704cb93a386Sopenharmony_ci        v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
705cb93a386Sopenharmony_ci        v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
706cb93a386Sopenharmony_ci        gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
707cb93a386Sopenharmony_ci
708cb93a386Sopenharmony_ci        // Setup interpolants for coverage.
709cb93a386Sopenharmony_ci        GrGLSLVarying arcCoord(useHWDerivatives ? kFloat2_GrSLType : kFloat4_GrSLType);
710cb93a386Sopenharmony_ci        varyings->addVarying("arccoord", &arcCoord);
711cb93a386Sopenharmony_ci        v->codeAppend("if (0 != is_linear_coverage) {");
712cb93a386Sopenharmony_ci                           // We are a non-corner piece: Set x=0 to indicate built-in coverage, and
713cb93a386Sopenharmony_ci                           // interpolate linear coverage across y.
714cb93a386Sopenharmony_ci        v->codeAppendf(    "%s.xy = float2(0, coverage * coverage_multiplier);",
715cb93a386Sopenharmony_ci                           arcCoord.vsOut());
716cb93a386Sopenharmony_ci        v->codeAppend("} else {");
717cb93a386Sopenharmony_ci                           // Find the normalized arc coordinates for our corner ellipse.
718cb93a386Sopenharmony_ci                           // (i.e., the coordinate system where x^2 + y^2 == 1).
719cb93a386Sopenharmony_ci        v->codeAppend(    "float2 arccoord = 1 - abs(radius_outset) + aa_outset/radii * corner;");
720cb93a386Sopenharmony_ci                           // We are a corner piece: Interpolate the arc coordinates for coverage.
721cb93a386Sopenharmony_ci                           // Emit x+1 to ensure no pixel in the arc has a x value of 0 (since x=0
722cb93a386Sopenharmony_ci                           // instructs the fragment shader to use linear coverage).
723cb93a386Sopenharmony_ci        v->codeAppendf(    "%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.vsOut());
724cb93a386Sopenharmony_ci        if (!useHWDerivatives) {
725cb93a386Sopenharmony_ci            // The gradient is order-1: Interpolate it across arccoord.zw.
726cb93a386Sopenharmony_ci            v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
727cb93a386Sopenharmony_ci            v->codeAppendf("%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.vsOut());
728cb93a386Sopenharmony_ci        }
729cb93a386Sopenharmony_ci        v->codeAppend("}");
730cb93a386Sopenharmony_ci
731cb93a386Sopenharmony_ci        // Emit the fragment shader.
732cb93a386Sopenharmony_ci        f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn());
733cb93a386Sopenharmony_ci        f->codeAppendf("half coverage;");
734cb93a386Sopenharmony_ci        f->codeAppendf("if (0 == x_plus_1) {");
735cb93a386Sopenharmony_ci        f->codeAppendf(    "coverage = half(y);");  // We are a non-arc pixel (linear coverage).
736cb93a386Sopenharmony_ci        f->codeAppendf("} else {");
737cb93a386Sopenharmony_ci        f->codeAppendf(    "float fn = x_plus_1 * (x_plus_1 - 2);");  // fn = (x+1)*(x-1) = x^2-1
738cb93a386Sopenharmony_ci        f->codeAppendf(    "fn = fma(y,y, fn);");  // fn = x^2 + y^2 - 1
739cb93a386Sopenharmony_ci        if (useHWDerivatives) {
740cb93a386Sopenharmony_ci            f->codeAppendf("float fnwidth = fwidth(fn);");
741cb93a386Sopenharmony_ci        } else {
742cb93a386Sopenharmony_ci            // The gradient is interpolated across arccoord.zw.
743cb93a386Sopenharmony_ci            f->codeAppendf("float gx=%s.z, gy=%s.w;", arcCoord.fsIn(), arcCoord.fsIn());
744cb93a386Sopenharmony_ci            f->codeAppendf("float fnwidth = abs(gx) + abs(gy);");
745cb93a386Sopenharmony_ci        }
746cb93a386Sopenharmony_ci        f->codeAppendf(    "coverage = .5 - half(fn/fnwidth);");
747cb93a386Sopenharmony_ci        if (proc.fFlags & ProcessorFlags::kMSAAEnabled) {
748cb93a386Sopenharmony_ci            // MSAA uses ramps larger than 1px, so we need to clamp in both branches.
749cb93a386Sopenharmony_ci            f->codeAppendf("}");
750cb93a386Sopenharmony_ci        }
751cb93a386Sopenharmony_ci        f->codeAppendf("coverage = clamp(coverage, 0, 1);");
752cb93a386Sopenharmony_ci        if (!(proc.fFlags & ProcessorFlags::kMSAAEnabled)) {
753cb93a386Sopenharmony_ci            // When not using MSAA, we only need to clamp in the "arc" branch.
754cb93a386Sopenharmony_ci            f->codeAppendf("}");
755cb93a386Sopenharmony_ci        }
756cb93a386Sopenharmony_ci        if (proc.fFlags & ProcessorFlags::kFakeNonAA) {
757cb93a386Sopenharmony_ci            f->codeAppendf("coverage = (coverage >= .5) ? 1 : 0;");
758cb93a386Sopenharmony_ci        }
759cb93a386Sopenharmony_ci        f->codeAppendf("half4 %s = half4(coverage);", args.fOutputCoverage);
760cb93a386Sopenharmony_ci    }
761cb93a386Sopenharmony_ci};
762cb93a386Sopenharmony_ci
763cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl> FillRRectOpImpl::Processor::makeProgramImpl(
764cb93a386Sopenharmony_ci        const GrShaderCaps&) const {
765cb93a386Sopenharmony_ci    return std::make_unique<Impl>();
766cb93a386Sopenharmony_ci}
767cb93a386Sopenharmony_ci
768cb93a386Sopenharmony_civoid FillRRectOpImpl::onCreateProgramInfo(const GrCaps* caps,
769cb93a386Sopenharmony_ci                                          SkArenaAlloc* arena,
770cb93a386Sopenharmony_ci                                          const GrSurfaceProxyView& writeView,
771cb93a386Sopenharmony_ci                                          bool usesMSAASurface,
772cb93a386Sopenharmony_ci                                          GrAppliedClip&& appliedClip,
773cb93a386Sopenharmony_ci                                          const GrDstProxyView& dstProxyView,
774cb93a386Sopenharmony_ci                                          GrXferBarrierFlags renderPassXferBarriers,
775cb93a386Sopenharmony_ci                                          GrLoadOp colorLoadOp) {
776cb93a386Sopenharmony_ci    if (usesMSAASurface) {
777cb93a386Sopenharmony_ci        fProcessorFlags |= ProcessorFlags::kMSAAEnabled;
778cb93a386Sopenharmony_ci    }
779cb93a386Sopenharmony_ci    GrGeometryProcessor* gp = Processor::Make(arena, fHelper.aaType(), fProcessorFlags);
780cb93a386Sopenharmony_ci    fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, usesMSAASurface,
781cb93a386Sopenharmony_ci                                             std::move(appliedClip), dstProxyView, gp,
782cb93a386Sopenharmony_ci                                             GrPrimitiveType::kTriangles, renderPassXferBarriers,
783cb93a386Sopenharmony_ci                                             colorLoadOp);
784cb93a386Sopenharmony_ci}
785cb93a386Sopenharmony_ci
786cb93a386Sopenharmony_civoid FillRRectOpImpl::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
787cb93a386Sopenharmony_ci    if (!fInstanceBuffer || !fIndexBuffer || !fVertexBuffer) {
788cb93a386Sopenharmony_ci        return;  // Setup failed.
789cb93a386Sopenharmony_ci    }
790cb93a386Sopenharmony_ci
791cb93a386Sopenharmony_ci    flushState->bindPipelineAndScissorClip(*fProgramInfo, this->bounds());
792cb93a386Sopenharmony_ci    flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
793cb93a386Sopenharmony_ci    flushState->bindBuffers(std::move(fIndexBuffer), std::move(fInstanceBuffer),
794cb93a386Sopenharmony_ci                            std::move(fVertexBuffer));
795cb93a386Sopenharmony_ci    flushState->drawIndexedInstanced(SK_ARRAY_COUNT(kIndexData), 0, fInstanceCount, fBaseInstance,
796cb93a386Sopenharmony_ci                                     0);
797cb93a386Sopenharmony_ci}
798cb93a386Sopenharmony_ci
799cb93a386Sopenharmony_ci// Will the given corner look good if we use HW derivatives?
800cb93a386Sopenharmony_cibool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2f& cornerRadii) {
801cb93a386Sopenharmony_ci    Sk2f devRadii = devScale * cornerRadii;
802cb93a386Sopenharmony_ci    if (devRadii[1] < devRadii[0]) {
803cb93a386Sopenharmony_ci        devRadii = SkNx_shuffle<1,0>(devRadii);
804cb93a386Sopenharmony_ci    }
805cb93a386Sopenharmony_ci    float minDevRadius = std::max(devRadii[0], 1.f);  // Shader clamps radius at a minimum of 1.
806cb93a386Sopenharmony_ci    // Is the gradient smooth enough for this corner look ok if we use hardware derivatives?
807cb93a386Sopenharmony_ci    // This threshold was arrived at subjevtively on an NVIDIA chip.
808cb93a386Sopenharmony_ci    return minDevRadius * minDevRadius * 5 > devRadii[1];
809cb93a386Sopenharmony_ci}
810cb93a386Sopenharmony_ci
811cb93a386Sopenharmony_cibool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const SkVector& cornerRadii) {
812cb93a386Sopenharmony_ci    return can_use_hw_derivatives_with_coverage(devScale, Sk2f::Load(&cornerRadii));
813cb93a386Sopenharmony_ci}
814cb93a386Sopenharmony_ci
815cb93a386Sopenharmony_ci// Will the given round rect look good if we use HW derivatives?
816cb93a386Sopenharmony_cibool can_use_hw_derivatives_with_coverage(const GrShaderCaps& shaderCaps,
817cb93a386Sopenharmony_ci                                          const SkMatrix& viewMatrix,
818cb93a386Sopenharmony_ci                                          const SkRRect& rrect) {
819cb93a386Sopenharmony_ci    if (!shaderCaps.shaderDerivativeSupport()) {
820cb93a386Sopenharmony_ci        return false;
821cb93a386Sopenharmony_ci    }
822cb93a386Sopenharmony_ci
823cb93a386Sopenharmony_ci    Sk2f x = Sk2f(viewMatrix.getScaleX(), viewMatrix.getSkewX());
824cb93a386Sopenharmony_ci    Sk2f y = Sk2f(viewMatrix.getSkewY(), viewMatrix.getScaleY());
825cb93a386Sopenharmony_ci    Sk2f devScale = (x*x + y*y).sqrt();
826cb93a386Sopenharmony_ci    switch (rrect.getType()) {
827cb93a386Sopenharmony_ci        case SkRRect::kEmpty_Type:
828cb93a386Sopenharmony_ci        case SkRRect::kRect_Type:
829cb93a386Sopenharmony_ci            return true;
830cb93a386Sopenharmony_ci
831cb93a386Sopenharmony_ci        case SkRRect::kOval_Type:
832cb93a386Sopenharmony_ci        case SkRRect::kSimple_Type:
833cb93a386Sopenharmony_ci            return can_use_hw_derivatives_with_coverage(devScale, rrect.getSimpleRadii());
834cb93a386Sopenharmony_ci
835cb93a386Sopenharmony_ci        case SkRRect::kNinePatch_Type: {
836cb93a386Sopenharmony_ci            Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect));
837cb93a386Sopenharmony_ci            Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2);
838cb93a386Sopenharmony_ci            Sk2f minRadii = Sk2f::Min(r0, r1);
839cb93a386Sopenharmony_ci            Sk2f maxRadii = Sk2f::Max(r0, r1);
840cb93a386Sopenharmony_ci            return can_use_hw_derivatives_with_coverage(devScale, Sk2f(minRadii[0], maxRadii[1])) &&
841cb93a386Sopenharmony_ci                   can_use_hw_derivatives_with_coverage(devScale, Sk2f(maxRadii[0], minRadii[1]));
842cb93a386Sopenharmony_ci        }
843cb93a386Sopenharmony_ci
844cb93a386Sopenharmony_ci        case SkRRect::kComplex_Type: {
845cb93a386Sopenharmony_ci            for (int i = 0; i < 4; ++i) {
846cb93a386Sopenharmony_ci                auto corner = static_cast<SkRRect::Corner>(i);
847cb93a386Sopenharmony_ci                if (!can_use_hw_derivatives_with_coverage(devScale, rrect.radii(corner))) {
848cb93a386Sopenharmony_ci                    return false;
849cb93a386Sopenharmony_ci                }
850cb93a386Sopenharmony_ci            }
851cb93a386Sopenharmony_ci            return true;
852cb93a386Sopenharmony_ci        }
853cb93a386Sopenharmony_ci    }
854cb93a386Sopenharmony_ci    SK_ABORT("Invalid round rect type.");
855cb93a386Sopenharmony_ci}
856cb93a386Sopenharmony_ci
857cb93a386Sopenharmony_ci} // anonymous namespace
858cb93a386Sopenharmony_ci
859cb93a386Sopenharmony_ciGrOp::Owner Make(GrRecordingContext* ctx,
860cb93a386Sopenharmony_ci                 SkArenaAlloc* arena,
861cb93a386Sopenharmony_ci                 GrPaint&& paint,
862cb93a386Sopenharmony_ci                 const SkMatrix& viewMatrix,
863cb93a386Sopenharmony_ci                 const SkRRect& rrect,
864cb93a386Sopenharmony_ci                 const SkRect& localRect,
865cb93a386Sopenharmony_ci                 GrAA aa) {
866cb93a386Sopenharmony_ci    return FillRRectOpImpl::Make(ctx, arena, std::move(paint), viewMatrix, rrect, localRect, aa);
867cb93a386Sopenharmony_ci}
868cb93a386Sopenharmony_ci
869cb93a386Sopenharmony_ci} // namespace skgpu::v1::FillRRectOp
870cb93a386Sopenharmony_ci
871cb93a386Sopenharmony_ci#if GR_TEST_UTILS
872cb93a386Sopenharmony_ci
873cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h"
874cb93a386Sopenharmony_ci
875cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(FillRRectOp) {
876cb93a386Sopenharmony_ci    SkArenaAlloc arena(64 * sizeof(float));
877cb93a386Sopenharmony_ci    SkMatrix viewMatrix = GrTest::TestMatrix(random);
878cb93a386Sopenharmony_ci    GrAA aa = GrAA(random->nextBool());
879cb93a386Sopenharmony_ci
880cb93a386Sopenharmony_ci    SkRect rect = GrTest::TestRect(random);
881cb93a386Sopenharmony_ci    float w = rect.width();
882cb93a386Sopenharmony_ci    float h = rect.height();
883cb93a386Sopenharmony_ci
884cb93a386Sopenharmony_ci    SkRRect rrect;
885cb93a386Sopenharmony_ci    // TODO: test out other rrect configurations
886cb93a386Sopenharmony_ci    rrect.setNinePatch(rect, w / 3.0f, h / 4.0f, w / 5.0f, h / 6.0);
887cb93a386Sopenharmony_ci
888cb93a386Sopenharmony_ci    return skgpu::v1::FillRRectOp::Make(context,
889cb93a386Sopenharmony_ci                                        &arena,
890cb93a386Sopenharmony_ci                                        std::move(paint),
891cb93a386Sopenharmony_ci                                        viewMatrix,
892cb93a386Sopenharmony_ci                                        rrect,
893cb93a386Sopenharmony_ci                                        rrect.rect(),
894cb93a386Sopenharmony_ci                                        aa);
895cb93a386Sopenharmony_ci}
896cb93a386Sopenharmony_ci
897cb93a386Sopenharmony_ci#endif
898