xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/FillRectOp.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2018 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/FillRectOp.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBuffer.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpsTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorSet.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProgramInfo.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceDrawContext.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrQuad.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrQuadBuffer.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrQuadUtils.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/QuadPerEdgeAA.h"
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDrawOpTest.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTestUtils.h"
44*c8dee2aaSAndroid Build Coastguard Worker #endif
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
47*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
48*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
49*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker class GrCaps;
52*c8dee2aaSAndroid Build Coastguard Worker class GrDstProxyView;
53*c8dee2aaSAndroid Build Coastguard Worker class GrSurfaceProxyView;
54*c8dee2aaSAndroid Build Coastguard Worker enum class GrXferBarrierFlags;
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker namespace {
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker using VertexSpec = skgpu::ganesh::QuadPerEdgeAA::VertexSpec;
59*c8dee2aaSAndroid Build Coastguard Worker using ColorType = skgpu::ganesh::QuadPerEdgeAA::ColorType;
60*c8dee2aaSAndroid Build Coastguard Worker using Subset = skgpu::ganesh::QuadPerEdgeAA::Subset;
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
dump_quad_info(int index,const GrQuad * deviceQuad,const GrQuad * localQuad,const SkPMColor4f & color,GrQuadAAFlags aaFlags)63*c8dee2aaSAndroid Build Coastguard Worker SkString dump_quad_info(int index, const GrQuad* deviceQuad,
64*c8dee2aaSAndroid Build Coastguard Worker                         const GrQuad* localQuad, const SkPMColor4f& color,
65*c8dee2aaSAndroid Build Coastguard Worker                         GrQuadAAFlags aaFlags) {
66*c8dee2aaSAndroid Build Coastguard Worker     GrQuad safeLocal = localQuad ? *localQuad : GrQuad();
67*c8dee2aaSAndroid Build Coastguard Worker     SkString str;
68*c8dee2aaSAndroid Build Coastguard Worker     str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
69*c8dee2aaSAndroid Build Coastguard Worker                 "  device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
70*c8dee2aaSAndroid Build Coastguard Worker                 "(%.2f, %.2f, %.2f)],\n"
71*c8dee2aaSAndroid Build Coastguard Worker                 "  local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
72*c8dee2aaSAndroid Build Coastguard Worker                 "(%.2f, %.2f, %.2f)]\n",
73*c8dee2aaSAndroid Build Coastguard Worker                 index, color.fR, color.fG, color.fB, color.fA,
74*c8dee2aaSAndroid Build Coastguard Worker                 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
75*c8dee2aaSAndroid Build Coastguard Worker                 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
76*c8dee2aaSAndroid Build Coastguard Worker                 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
77*c8dee2aaSAndroid Build Coastguard Worker                 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
78*c8dee2aaSAndroid Build Coastguard Worker                 deviceQuad->x(0), deviceQuad->y(0), deviceQuad->w(0),
79*c8dee2aaSAndroid Build Coastguard Worker                 deviceQuad->x(1), deviceQuad->y(1), deviceQuad->w(1),
80*c8dee2aaSAndroid Build Coastguard Worker                 deviceQuad->x(2), deviceQuad->y(2), deviceQuad->w(2),
81*c8dee2aaSAndroid Build Coastguard Worker                 deviceQuad->x(3), deviceQuad->y(3), deviceQuad->w(3),
82*c8dee2aaSAndroid Build Coastguard Worker                 safeLocal.x(0), safeLocal.y(0), safeLocal.w(0),
83*c8dee2aaSAndroid Build Coastguard Worker                 safeLocal.x(1), safeLocal.y(1), safeLocal.w(1),
84*c8dee2aaSAndroid Build Coastguard Worker                 safeLocal.x(2), safeLocal.y(2), safeLocal.w(2),
85*c8dee2aaSAndroid Build Coastguard Worker                 safeLocal.x(3), safeLocal.y(3), safeLocal.w(3));
86*c8dee2aaSAndroid Build Coastguard Worker     return str;
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker #endif
89*c8dee2aaSAndroid Build Coastguard Worker 
90*c8dee2aaSAndroid Build Coastguard Worker class FillRectOpImpl final : public GrMeshDrawOp {
91*c8dee2aaSAndroid Build Coastguard Worker private:
92*c8dee2aaSAndroid Build Coastguard Worker     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
93*c8dee2aaSAndroid Build Coastguard Worker 
94*c8dee2aaSAndroid Build Coastguard Worker public:
Make(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,DrawQuad * quad,const GrUserStencilSettings * stencilSettings,Helper::InputFlags inputFlags)95*c8dee2aaSAndroid Build Coastguard Worker     static GrOp::Owner Make(GrRecordingContext* context,
96*c8dee2aaSAndroid Build Coastguard Worker                             GrPaint&& paint,
97*c8dee2aaSAndroid Build Coastguard Worker                             GrAAType aaType,
98*c8dee2aaSAndroid Build Coastguard Worker                             DrawQuad* quad,
99*c8dee2aaSAndroid Build Coastguard Worker                             const GrUserStencilSettings* stencilSettings,
100*c8dee2aaSAndroid Build Coastguard Worker                             Helper::InputFlags inputFlags) {
101*c8dee2aaSAndroid Build Coastguard Worker         // Clean up deviations between aaType and edgeAA
102*c8dee2aaSAndroid Build Coastguard Worker         GrQuadUtils::ResolveAAType(aaType, quad->fEdgeFlags, quad->fDevice,
103*c8dee2aaSAndroid Build Coastguard Worker                                    &aaType, &quad->fEdgeFlags);
104*c8dee2aaSAndroid Build Coastguard Worker         return Helper::FactoryHelper<FillRectOpImpl>(context, std::move(paint), aaType, quad,
105*c8dee2aaSAndroid Build Coastguard Worker                                                      stencilSettings, inputFlags);
106*c8dee2aaSAndroid Build Coastguard Worker     }
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker     // aaType is passed to Helper in the initializer list, so incongruities between aaType and
109*c8dee2aaSAndroid Build Coastguard Worker     // edgeFlags must be resolved prior to calling this constructor.
FillRectOpImpl(GrProcessorSet * processorSet,SkPMColor4f paintColor,GrAAType aaType,DrawQuad * quad,const GrUserStencilSettings * stencil,Helper::InputFlags inputFlags)110*c8dee2aaSAndroid Build Coastguard Worker     FillRectOpImpl(GrProcessorSet* processorSet, SkPMColor4f paintColor, GrAAType aaType,
111*c8dee2aaSAndroid Build Coastguard Worker                    DrawQuad* quad, const GrUserStencilSettings* stencil,
112*c8dee2aaSAndroid Build Coastguard Worker                    Helper::InputFlags inputFlags)
113*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(ClassID())
114*c8dee2aaSAndroid Build Coastguard Worker             , fHelper(processorSet, aaType, stencil, inputFlags)
115*c8dee2aaSAndroid Build Coastguard Worker             , fQuads(1, !fHelper.isTrivial()) {
116*c8dee2aaSAndroid Build Coastguard Worker         // Set bounds before clipping so we don't have to worry about unioning the bounds of
117*c8dee2aaSAndroid Build Coastguard Worker         // the two potential quads (GrQuad::bounds() is perspective-safe).
118*c8dee2aaSAndroid Build Coastguard Worker         bool hairline = GrQuadUtils::WillUseHairline(quad->fDevice, aaType, quad->fEdgeFlags);
119*c8dee2aaSAndroid Build Coastguard Worker         this->setBounds(quad->fDevice.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
120*c8dee2aaSAndroid Build Coastguard Worker                         hairline ? IsHairline::kYes : IsHairline::kNo);
121*c8dee2aaSAndroid Build Coastguard Worker         DrawQuad extra;
122*c8dee2aaSAndroid Build Coastguard Worker         // Always crop to W>0 to remain consistent with GrQuad::bounds()
123*c8dee2aaSAndroid Build Coastguard Worker         int count = GrQuadUtils::ClipToW0(quad, &extra);
124*c8dee2aaSAndroid Build Coastguard Worker         if (count == 0) {
125*c8dee2aaSAndroid Build Coastguard Worker             // We can't discard the op at this point, but disable AA flags so it won't go through
126*c8dee2aaSAndroid Build Coastguard Worker             // inset/outset processing
127*c8dee2aaSAndroid Build Coastguard Worker             quad->fEdgeFlags = GrQuadAAFlags::kNone;
128*c8dee2aaSAndroid Build Coastguard Worker             count = 1;
129*c8dee2aaSAndroid Build Coastguard Worker         }
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker         // Conservatively keep track of the local coordinates; it may be that the paint doesn't
132*c8dee2aaSAndroid Build Coastguard Worker         // need them after analysis is finished. If the paint is known to be solid up front they
133*c8dee2aaSAndroid Build Coastguard Worker         // can be skipped entirely.
134*c8dee2aaSAndroid Build Coastguard Worker         fQuads.append(quad->fDevice, {paintColor, quad->fEdgeFlags},
135*c8dee2aaSAndroid Build Coastguard Worker                       fHelper.isTrivial() ? nullptr : &quad->fLocal);
136*c8dee2aaSAndroid Build Coastguard Worker         if (count > 1) {
137*c8dee2aaSAndroid Build Coastguard Worker             fQuads.append(extra.fDevice, { paintColor, extra.fEdgeFlags },
138*c8dee2aaSAndroid Build Coastguard Worker                           fHelper.isTrivial() ? nullptr : &extra.fLocal);
139*c8dee2aaSAndroid Build Coastguard Worker         }
140*c8dee2aaSAndroid Build Coastguard Worker     }
141*c8dee2aaSAndroid Build Coastguard Worker 
name() const142*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "FillRectOp"; }
143*c8dee2aaSAndroid Build Coastguard Worker 
visitProxies(const GrVisitProxyFunc & func) const144*c8dee2aaSAndroid Build Coastguard Worker     void visitProxies(const GrVisitProxyFunc& func) const override {
145*c8dee2aaSAndroid Build Coastguard Worker         if (fProgramInfo) {
146*c8dee2aaSAndroid Build Coastguard Worker             fProgramInfo->visitFPProxies(func);
147*c8dee2aaSAndroid Build Coastguard Worker         } else {
148*c8dee2aaSAndroid Build Coastguard Worker             return fHelper.visitProxies(func);
149*c8dee2aaSAndroid Build Coastguard Worker         }
150*c8dee2aaSAndroid Build Coastguard Worker     }
151*c8dee2aaSAndroid Build Coastguard Worker 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)152*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
153*c8dee2aaSAndroid Build Coastguard Worker                                       GrClampType clampType) override {
154*c8dee2aaSAndroid Build Coastguard Worker         // Initialize aggregate color analysis with the first quad's color (which always exists)
155*c8dee2aaSAndroid Build Coastguard Worker         auto iter = fQuads.metadata();
156*c8dee2aaSAndroid Build Coastguard Worker         SkAssertResult(iter.next());
157*c8dee2aaSAndroid Build Coastguard Worker         GrProcessorAnalysisColor quadColors(iter->fColor);
158*c8dee2aaSAndroid Build Coastguard Worker         // Then combine the colors of any additional quads (e.g. from MakeSet)
159*c8dee2aaSAndroid Build Coastguard Worker         while(iter.next()) {
160*c8dee2aaSAndroid Build Coastguard Worker             quadColors = GrProcessorAnalysisColor::Combine(quadColors, iter->fColor);
161*c8dee2aaSAndroid Build Coastguard Worker             if (quadColors.isUnknown()) {
162*c8dee2aaSAndroid Build Coastguard Worker                 // No point in accumulating additional starting colors, combining cannot make it
163*c8dee2aaSAndroid Build Coastguard Worker                 // less unknown.
164*c8dee2aaSAndroid Build Coastguard Worker                 break;
165*c8dee2aaSAndroid Build Coastguard Worker             }
166*c8dee2aaSAndroid Build Coastguard Worker         }
167*c8dee2aaSAndroid Build Coastguard Worker 
168*c8dee2aaSAndroid Build Coastguard Worker         // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
169*c8dee2aaSAndroid Build Coastguard Worker         // then the coverage is always 1.0, so specify kNone for more optimal blending.
170*c8dee2aaSAndroid Build Coastguard Worker         auto coverage = fHelper.aaType() == GrAAType::kCoverage
171*c8dee2aaSAndroid Build Coastguard Worker                                                     ? GrProcessorAnalysisCoverage::kSingleChannel
172*c8dee2aaSAndroid Build Coastguard Worker                                                     : GrProcessorAnalysisCoverage::kNone;
173*c8dee2aaSAndroid Build Coastguard Worker         auto result = fHelper.finalizeProcessors(caps, clip, clampType, coverage, &quadColors);
174*c8dee2aaSAndroid Build Coastguard Worker         // If there is a constant color after analysis, that means all of the quads should be set
175*c8dee2aaSAndroid Build Coastguard Worker         // to the same color (even if they started out with different colors).
176*c8dee2aaSAndroid Build Coastguard Worker         iter = fQuads.metadata();
177*c8dee2aaSAndroid Build Coastguard Worker         SkPMColor4f colorOverride;
178*c8dee2aaSAndroid Build Coastguard Worker         if (quadColors.isConstant(&colorOverride)) {
179*c8dee2aaSAndroid Build Coastguard Worker             fColorType = skgpu::ganesh::QuadPerEdgeAA::MinColorType(colorOverride);
180*c8dee2aaSAndroid Build Coastguard Worker             while(iter.next()) {
181*c8dee2aaSAndroid Build Coastguard Worker                 iter->fColor = colorOverride;
182*c8dee2aaSAndroid Build Coastguard Worker             }
183*c8dee2aaSAndroid Build Coastguard Worker         } else {
184*c8dee2aaSAndroid Build Coastguard Worker             // Otherwise compute the color type needed as the max over all quads.
185*c8dee2aaSAndroid Build Coastguard Worker             fColorType = ColorType::kNone;
186*c8dee2aaSAndroid Build Coastguard Worker             while(iter.next()) {
187*c8dee2aaSAndroid Build Coastguard Worker                 fColorType = std::max(fColorType,
188*c8dee2aaSAndroid Build Coastguard Worker                                       skgpu::ganesh::QuadPerEdgeAA::MinColorType(iter->fColor));
189*c8dee2aaSAndroid Build Coastguard Worker             }
190*c8dee2aaSAndroid Build Coastguard Worker         }
191*c8dee2aaSAndroid Build Coastguard Worker         // Most SkShaders' FPs multiply their calculated color by the paint color or alpha. We want
192*c8dee2aaSAndroid Build Coastguard Worker         // to use ColorType::kNone to optimize out that multiply. However, if there are no color
193*c8dee2aaSAndroid Build Coastguard Worker         // FPs then were really writing a special shader for white rectangles and not saving any
194*c8dee2aaSAndroid Build Coastguard Worker         // multiples. So in that case use bytes to avoid the extra shader (and possibly work around
195*c8dee2aaSAndroid Build Coastguard Worker         // an ANGLE issue: crbug.com/942565).
196*c8dee2aaSAndroid Build Coastguard Worker         if (fColorType == ColorType::kNone && !result.hasColorFragmentProcessor()) {
197*c8dee2aaSAndroid Build Coastguard Worker             fColorType = ColorType::kByte;
198*c8dee2aaSAndroid Build Coastguard Worker         }
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker         return result;
201*c8dee2aaSAndroid Build Coastguard Worker     }
202*c8dee2aaSAndroid Build Coastguard Worker 
fixedFunctionFlags() const203*c8dee2aaSAndroid Build Coastguard Worker     FixedFunctionFlags fixedFunctionFlags() const override {
204*c8dee2aaSAndroid Build Coastguard Worker         // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
205*c8dee2aaSAndroid Build Coastguard Worker         // the helper's fixed function flags are appropriate.
206*c8dee2aaSAndroid Build Coastguard Worker         return fHelper.fixedFunctionFlags();
207*c8dee2aaSAndroid Build Coastguard Worker     }
208*c8dee2aaSAndroid Build Coastguard Worker 
209*c8dee2aaSAndroid Build Coastguard Worker     DEFINE_OP_CLASS_ID
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker private:
212*c8dee2aaSAndroid Build Coastguard Worker     friend class skgpu::ganesh::FillRectOp;  // for access to addQuad
213*c8dee2aaSAndroid Build Coastguard Worker 
214*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
numQuads() const215*c8dee2aaSAndroid Build Coastguard Worker     int numQuads() const final { return fQuads.count(); }
216*c8dee2aaSAndroid Build Coastguard Worker #endif
217*c8dee2aaSAndroid Build Coastguard Worker 
vertexSpec() const218*c8dee2aaSAndroid Build Coastguard Worker     VertexSpec vertexSpec() const {
219*c8dee2aaSAndroid Build Coastguard Worker         auto indexBufferOption = skgpu::ganesh::QuadPerEdgeAA::CalcIndexBufferOption(
220*c8dee2aaSAndroid Build Coastguard Worker                 fHelper.aaType(), fQuads.count());
221*c8dee2aaSAndroid Build Coastguard Worker 
222*c8dee2aaSAndroid Build Coastguard Worker         return VertexSpec(fQuads.deviceQuadType(), fColorType, fQuads.localQuadType(),
223*c8dee2aaSAndroid Build Coastguard Worker                           fHelper.usesLocalCoords(), Subset::kNo, fHelper.aaType(),
224*c8dee2aaSAndroid Build Coastguard Worker                           fHelper.compatibleWithCoverageAsAlpha(), indexBufferOption);
225*c8dee2aaSAndroid Build Coastguard Worker     }
226*c8dee2aaSAndroid Build Coastguard Worker 
programInfo()227*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo* programInfo() override {
228*c8dee2aaSAndroid Build Coastguard Worker         return fProgramInfo;
229*c8dee2aaSAndroid Build Coastguard Worker     }
230*c8dee2aaSAndroid Build Coastguard Worker 
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)231*c8dee2aaSAndroid Build Coastguard Worker     void onCreateProgramInfo(const GrCaps* caps,
232*c8dee2aaSAndroid Build Coastguard Worker                              SkArenaAlloc* arena,
233*c8dee2aaSAndroid Build Coastguard Worker                              const GrSurfaceProxyView& writeView,
234*c8dee2aaSAndroid Build Coastguard Worker                              bool usesMSAASurface,
235*c8dee2aaSAndroid Build Coastguard Worker                              GrAppliedClip&& appliedClip,
236*c8dee2aaSAndroid Build Coastguard Worker                              const GrDstProxyView& dstProxyView,
237*c8dee2aaSAndroid Build Coastguard Worker                              GrXferBarrierFlags renderPassXferBarriers,
238*c8dee2aaSAndroid Build Coastguard Worker                              GrLoadOp colorLoadOp) override {
239*c8dee2aaSAndroid Build Coastguard Worker         const VertexSpec vertexSpec = this->vertexSpec();
240*c8dee2aaSAndroid Build Coastguard Worker 
241*c8dee2aaSAndroid Build Coastguard Worker         GrGeometryProcessor* gp = skgpu::ganesh::QuadPerEdgeAA::MakeProcessor(arena, vertexSpec);
242*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(gp->vertexStride() == vertexSpec.vertexSize());
243*c8dee2aaSAndroid Build Coastguard Worker 
244*c8dee2aaSAndroid Build Coastguard Worker         fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, usesMSAASurface,
245*c8dee2aaSAndroid Build Coastguard Worker                                                             std::move(appliedClip),
246*c8dee2aaSAndroid Build Coastguard Worker                                                             dstProxyView, gp,
247*c8dee2aaSAndroid Build Coastguard Worker                                                             vertexSpec.primitiveType(),
248*c8dee2aaSAndroid Build Coastguard Worker                                                             renderPassXferBarriers, colorLoadOp);
249*c8dee2aaSAndroid Build Coastguard Worker     }
250*c8dee2aaSAndroid Build Coastguard Worker 
onPrePrepareDraws(GrRecordingContext * rContext,const GrSurfaceProxyView & writeView,GrAppliedClip * clip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)251*c8dee2aaSAndroid Build Coastguard Worker     void onPrePrepareDraws(GrRecordingContext* rContext,
252*c8dee2aaSAndroid Build Coastguard Worker                            const GrSurfaceProxyView& writeView,
253*c8dee2aaSAndroid Build Coastguard Worker                            GrAppliedClip* clip,
254*c8dee2aaSAndroid Build Coastguard Worker                            const GrDstProxyView& dstProxyView,
255*c8dee2aaSAndroid Build Coastguard Worker                            GrXferBarrierFlags renderPassXferBarriers,
256*c8dee2aaSAndroid Build Coastguard Worker                            GrLoadOp colorLoadOp) override {
257*c8dee2aaSAndroid Build Coastguard Worker         TRACE_EVENT0("skia.gpu", TRACE_FUNC);
258*c8dee2aaSAndroid Build Coastguard Worker 
259*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fPrePreparedVertices);
260*c8dee2aaSAndroid Build Coastguard Worker 
261*c8dee2aaSAndroid Build Coastguard Worker         INHERITED::onPrePrepareDraws(rContext, writeView, clip, dstProxyView,
262*c8dee2aaSAndroid Build Coastguard Worker                                      renderPassXferBarriers, colorLoadOp);
263*c8dee2aaSAndroid Build Coastguard Worker 
264*c8dee2aaSAndroid Build Coastguard Worker         SkArenaAlloc* arena = rContext->priv().recordTimeAllocator();
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker         const VertexSpec vertexSpec = this->vertexSpec();
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker         const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
269*c8dee2aaSAndroid Build Coastguard Worker         const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
270*c8dee2aaSAndroid Build Coastguard Worker 
271*c8dee2aaSAndroid Build Coastguard Worker         fPrePreparedVertices = arena->makeArrayDefault<char>(totalVertexSizeInBytes);
272*c8dee2aaSAndroid Build Coastguard Worker 
273*c8dee2aaSAndroid Build Coastguard Worker         this->tessellate(vertexSpec, fPrePreparedVertices);
274*c8dee2aaSAndroid Build Coastguard Worker     }
275*c8dee2aaSAndroid Build Coastguard Worker 
tessellate(const VertexSpec & vertexSpec,char * dst) const276*c8dee2aaSAndroid Build Coastguard Worker     void tessellate(const VertexSpec& vertexSpec, char* dst) const {
277*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker         skgpu::ganesh::QuadPerEdgeAA::Tessellator tessellator(vertexSpec, dst);
280*c8dee2aaSAndroid Build Coastguard Worker         auto iter = fQuads.iterator();
281*c8dee2aaSAndroid Build Coastguard Worker         while (iter.next()) {
282*c8dee2aaSAndroid Build Coastguard Worker             // All entries should have local coords, or no entries should have local coords,
283*c8dee2aaSAndroid Build Coastguard Worker             // matching !helper.isTrivial() (which is more conservative than helper.usesLocalCoords)
284*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(iter.isLocalValid() != fHelper.isTrivial());
285*c8dee2aaSAndroid Build Coastguard Worker             auto info = iter.metadata();
286*c8dee2aaSAndroid Build Coastguard Worker             tessellator.append(iter.deviceQuad(), iter.localQuad(),
287*c8dee2aaSAndroid Build Coastguard Worker                                info.fColor, kEmptyDomain, info.fAAFlags);
288*c8dee2aaSAndroid Build Coastguard Worker         }
289*c8dee2aaSAndroid Build Coastguard Worker     }
290*c8dee2aaSAndroid Build Coastguard Worker 
onPrepareDraws(GrMeshDrawTarget * target)291*c8dee2aaSAndroid Build Coastguard Worker     void onPrepareDraws(GrMeshDrawTarget* target) override {
292*c8dee2aaSAndroid Build Coastguard Worker         TRACE_EVENT0("skia.gpu", TRACE_FUNC);
293*c8dee2aaSAndroid Build Coastguard Worker 
294*c8dee2aaSAndroid Build Coastguard Worker         const VertexSpec vertexSpec = this->vertexSpec();
295*c8dee2aaSAndroid Build Coastguard Worker 
296*c8dee2aaSAndroid Build Coastguard Worker         // Make sure that if the op thought it was a solid color, the vertex spec does not use
297*c8dee2aaSAndroid Build Coastguard Worker         // local coords.
298*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
299*c8dee2aaSAndroid Build Coastguard Worker 
300*c8dee2aaSAndroid Build Coastguard Worker         const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
301*c8dee2aaSAndroid Build Coastguard Worker 
302*c8dee2aaSAndroid Build Coastguard Worker         // Fill the allocated vertex data
303*c8dee2aaSAndroid Build Coastguard Worker         void* vdata = target->makeVertexSpace(vertexSpec.vertexSize(), totalNumVertices,
304*c8dee2aaSAndroid Build Coastguard Worker                                               &fVertexBuffer, &fBaseVertex);
305*c8dee2aaSAndroid Build Coastguard Worker         if (!vdata) {
306*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("Could not allocate vertices\n");
307*c8dee2aaSAndroid Build Coastguard Worker             return;
308*c8dee2aaSAndroid Build Coastguard Worker         }
309*c8dee2aaSAndroid Build Coastguard Worker 
310*c8dee2aaSAndroid Build Coastguard Worker         if (fPrePreparedVertices) {
311*c8dee2aaSAndroid Build Coastguard Worker             const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
312*c8dee2aaSAndroid Build Coastguard Worker 
313*c8dee2aaSAndroid Build Coastguard Worker             memcpy(vdata, fPrePreparedVertices, totalVertexSizeInBytes);
314*c8dee2aaSAndroid Build Coastguard Worker         } else {
315*c8dee2aaSAndroid Build Coastguard Worker             this->tessellate(vertexSpec, (char*) vdata);
316*c8dee2aaSAndroid Build Coastguard Worker         }
317*c8dee2aaSAndroid Build Coastguard Worker 
318*c8dee2aaSAndroid Build Coastguard Worker         if (vertexSpec.needsIndexBuffer()) {
319*c8dee2aaSAndroid Build Coastguard Worker             fIndexBuffer = skgpu::ganesh::QuadPerEdgeAA::GetIndexBuffer(
320*c8dee2aaSAndroid Build Coastguard Worker                     target, vertexSpec.indexBufferOption());
321*c8dee2aaSAndroid Build Coastguard Worker             if (!fIndexBuffer) {
322*c8dee2aaSAndroid Build Coastguard Worker                 SkDebugf("Could not allocate indices\n");
323*c8dee2aaSAndroid Build Coastguard Worker                 return;
324*c8dee2aaSAndroid Build Coastguard Worker             }
325*c8dee2aaSAndroid Build Coastguard Worker         }
326*c8dee2aaSAndroid Build Coastguard Worker     }
327*c8dee2aaSAndroid Build Coastguard Worker 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)328*c8dee2aaSAndroid Build Coastguard Worker     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
329*c8dee2aaSAndroid Build Coastguard Worker         if (!fVertexBuffer) {
330*c8dee2aaSAndroid Build Coastguard Worker             return;
331*c8dee2aaSAndroid Build Coastguard Worker         }
332*c8dee2aaSAndroid Build Coastguard Worker 
333*c8dee2aaSAndroid Build Coastguard Worker         const VertexSpec vertexSpec = this->vertexSpec();
334*c8dee2aaSAndroid Build Coastguard Worker 
335*c8dee2aaSAndroid Build Coastguard Worker         if (vertexSpec.needsIndexBuffer() && !fIndexBuffer) {
336*c8dee2aaSAndroid Build Coastguard Worker             return;
337*c8dee2aaSAndroid Build Coastguard Worker         }
338*c8dee2aaSAndroid Build Coastguard Worker 
339*c8dee2aaSAndroid Build Coastguard Worker         if (!fProgramInfo) {
340*c8dee2aaSAndroid Build Coastguard Worker             this->createProgramInfo(flushState);
341*c8dee2aaSAndroid Build Coastguard Worker         }
342*c8dee2aaSAndroid Build Coastguard Worker 
343*c8dee2aaSAndroid Build Coastguard Worker         const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
344*c8dee2aaSAndroid Build Coastguard Worker 
345*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
346*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindBuffers(std::move(fIndexBuffer), nullptr, std::move(fVertexBuffer));
347*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
348*c8dee2aaSAndroid Build Coastguard Worker         skgpu::ganesh::QuadPerEdgeAA::IssueDraw(flushState->caps(),
349*c8dee2aaSAndroid Build Coastguard Worker                                                 flushState->opsRenderPass(),
350*c8dee2aaSAndroid Build Coastguard Worker                                                 vertexSpec,
351*c8dee2aaSAndroid Build Coastguard Worker                                                 0,
352*c8dee2aaSAndroid Build Coastguard Worker                                                 fQuads.count(),
353*c8dee2aaSAndroid Build Coastguard Worker                                                 totalNumVertices,
354*c8dee2aaSAndroid Build Coastguard Worker                                                 fBaseVertex);
355*c8dee2aaSAndroid Build Coastguard Worker     }
356*c8dee2aaSAndroid Build Coastguard Worker 
onCombineIfPossible(GrOp * t,SkArenaAlloc *,const GrCaps & caps)357*c8dee2aaSAndroid Build Coastguard Worker     CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
358*c8dee2aaSAndroid Build Coastguard Worker         TRACE_EVENT0("skia.gpu", TRACE_FUNC);
359*c8dee2aaSAndroid Build Coastguard Worker         auto that = t->cast<FillRectOpImpl>();
360*c8dee2aaSAndroid Build Coastguard Worker 
361*c8dee2aaSAndroid Build Coastguard Worker         bool upgradeToCoverageAAOnMerge = false;
362*c8dee2aaSAndroid Build Coastguard Worker         if (fHelper.aaType() != that->fHelper.aaType()) {
363*c8dee2aaSAndroid Build Coastguard Worker             if (!CanUpgradeAAOnMerge(fHelper.aaType(), that->fHelper.aaType())) {
364*c8dee2aaSAndroid Build Coastguard Worker                 return CombineResult::kCannotCombine;
365*c8dee2aaSAndroid Build Coastguard Worker             }
366*c8dee2aaSAndroid Build Coastguard Worker             upgradeToCoverageAAOnMerge = true;
367*c8dee2aaSAndroid Build Coastguard Worker         }
368*c8dee2aaSAndroid Build Coastguard Worker 
369*c8dee2aaSAndroid Build Coastguard Worker         if (CombinedQuadCountWillOverflow(fHelper.aaType(), upgradeToCoverageAAOnMerge,
370*c8dee2aaSAndroid Build Coastguard Worker                                           fQuads.count() + that->fQuads.count())) {
371*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
372*c8dee2aaSAndroid Build Coastguard Worker         }
373*c8dee2aaSAndroid Build Coastguard Worker 
374*c8dee2aaSAndroid Build Coastguard Worker         // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
375*c8dee2aaSAndroid Build Coastguard Worker         // ops together, so pass true as the last argument.
376*c8dee2aaSAndroid Build Coastguard Worker         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
377*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
378*c8dee2aaSAndroid Build Coastguard Worker         }
379*c8dee2aaSAndroid Build Coastguard Worker 
380*c8dee2aaSAndroid Build Coastguard Worker         // If the paints were compatible, the trivial/solid-color state should be the same
381*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
382*c8dee2aaSAndroid Build Coastguard Worker 
383*c8dee2aaSAndroid Build Coastguard Worker         // If the processor sets are compatible, the two ops are always compatible; it just needs to
384*c8dee2aaSAndroid Build Coastguard Worker         // adjust the state of the op to be the more general quad and aa types of the two ops and
385*c8dee2aaSAndroid Build Coastguard Worker         // then concatenate the per-quad data.
386*c8dee2aaSAndroid Build Coastguard Worker         fColorType = std::max(fColorType, that->fColorType);
387*c8dee2aaSAndroid Build Coastguard Worker 
388*c8dee2aaSAndroid Build Coastguard Worker         // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
389*c8dee2aaSAndroid Build Coastguard Worker         // types to be none and coverage, in which case this op's aa type must be lifted to coverage
390*c8dee2aaSAndroid Build Coastguard Worker         // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
391*c8dee2aaSAndroid Build Coastguard Worker         if (upgradeToCoverageAAOnMerge) {
392*c8dee2aaSAndroid Build Coastguard Worker             fHelper.setAAType(GrAAType::kCoverage);
393*c8dee2aaSAndroid Build Coastguard Worker         }
394*c8dee2aaSAndroid Build Coastguard Worker 
395*c8dee2aaSAndroid Build Coastguard Worker         fQuads.concat(that->fQuads);
396*c8dee2aaSAndroid Build Coastguard Worker         return CombineResult::kMerged;
397*c8dee2aaSAndroid Build Coastguard Worker     }
398*c8dee2aaSAndroid Build Coastguard Worker 
399*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
onDumpInfo() const400*c8dee2aaSAndroid Build Coastguard Worker     SkString onDumpInfo() const override {
401*c8dee2aaSAndroid Build Coastguard Worker         SkString str = SkStringPrintf("# draws: %d\n", fQuads.count());
402*c8dee2aaSAndroid Build Coastguard Worker         str.appendf("Device quad type: %u, local quad type: %u\n",
403*c8dee2aaSAndroid Build Coastguard Worker                     (uint32_t) fQuads.deviceQuadType(), (uint32_t) fQuads.localQuadType());
404*c8dee2aaSAndroid Build Coastguard Worker         str += fHelper.dumpInfo();
405*c8dee2aaSAndroid Build Coastguard Worker         int i = 0;
406*c8dee2aaSAndroid Build Coastguard Worker         auto iter = fQuads.iterator();
407*c8dee2aaSAndroid Build Coastguard Worker         while(iter.next()) {
408*c8dee2aaSAndroid Build Coastguard Worker             const ColorAndAA& info = iter.metadata();
409*c8dee2aaSAndroid Build Coastguard Worker             str += dump_quad_info(i, iter.deviceQuad(), iter.localQuad(),
410*c8dee2aaSAndroid Build Coastguard Worker                                   info.fColor, info.fAAFlags);
411*c8dee2aaSAndroid Build Coastguard Worker             i++;
412*c8dee2aaSAndroid Build Coastguard Worker         }
413*c8dee2aaSAndroid Build Coastguard Worker         return str;
414*c8dee2aaSAndroid Build Coastguard Worker     }
415*c8dee2aaSAndroid Build Coastguard Worker #endif
416*c8dee2aaSAndroid Build Coastguard Worker 
canAddQuads(int numQuads,GrAAType aaType)417*c8dee2aaSAndroid Build Coastguard Worker     bool canAddQuads(int numQuads, GrAAType aaType) {
418*c8dee2aaSAndroid Build Coastguard Worker         // The new quad's aa type should be the same as the first quad's or none, except when the
419*c8dee2aaSAndroid Build Coastguard Worker         // first quad's aa type was already downgraded to none, in which case the stored type must
420*c8dee2aaSAndroid Build Coastguard Worker         // be lifted to back to the requested type.
421*c8dee2aaSAndroid Build Coastguard Worker         int quadCount = fQuads.count() + numQuads;
422*c8dee2aaSAndroid Build Coastguard Worker         if (aaType != fHelper.aaType() && aaType != GrAAType::kNone) {
423*c8dee2aaSAndroid Build Coastguard Worker             auto indexBufferOption =
424*c8dee2aaSAndroid Build Coastguard Worker                     skgpu::ganesh::QuadPerEdgeAA::CalcIndexBufferOption(aaType, quadCount);
425*c8dee2aaSAndroid Build Coastguard Worker             if (quadCount > skgpu::ganesh::QuadPerEdgeAA::QuadLimit(indexBufferOption)) {
426*c8dee2aaSAndroid Build Coastguard Worker                 // Promoting to the new aaType would've caused an overflow of the indexBuffer
427*c8dee2aaSAndroid Build Coastguard Worker                 // limit
428*c8dee2aaSAndroid Build Coastguard Worker                 return false;
429*c8dee2aaSAndroid Build Coastguard Worker             }
430*c8dee2aaSAndroid Build Coastguard Worker 
431*c8dee2aaSAndroid Build Coastguard Worker             // Original quad was downgraded to non-aa, lift back up to this quad's required type
432*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fHelper.aaType() == GrAAType::kNone);
433*c8dee2aaSAndroid Build Coastguard Worker             fHelper.setAAType(aaType);
434*c8dee2aaSAndroid Build Coastguard Worker         } else {
435*c8dee2aaSAndroid Build Coastguard Worker             auto indexBufferOption = skgpu::ganesh::QuadPerEdgeAA::CalcIndexBufferOption(
436*c8dee2aaSAndroid Build Coastguard Worker                     fHelper.aaType(), quadCount);
437*c8dee2aaSAndroid Build Coastguard Worker             if (quadCount > skgpu::ganesh::QuadPerEdgeAA::QuadLimit(indexBufferOption)) {
438*c8dee2aaSAndroid Build Coastguard Worker                 return false; // This op can't grow any more
439*c8dee2aaSAndroid Build Coastguard Worker             }
440*c8dee2aaSAndroid Build Coastguard Worker         }
441*c8dee2aaSAndroid Build Coastguard Worker 
442*c8dee2aaSAndroid Build Coastguard Worker         return true;
443*c8dee2aaSAndroid Build Coastguard Worker     }
444*c8dee2aaSAndroid Build Coastguard Worker 
445*c8dee2aaSAndroid Build Coastguard Worker     // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
446*c8dee2aaSAndroid Build Coastguard Worker     // But since it's avoiding the op list management, it must update the op's bounds.
addQuad(DrawQuad * quad,const SkPMColor4f & color,GrAAType aaType)447*c8dee2aaSAndroid Build Coastguard Worker     bool addQuad(DrawQuad* quad, const SkPMColor4f& color, GrAAType aaType) {
448*c8dee2aaSAndroid Build Coastguard Worker         SkRect newBounds = this->bounds();
449*c8dee2aaSAndroid Build Coastguard Worker         newBounds.joinPossiblyEmptyRect(quad->fDevice.bounds());
450*c8dee2aaSAndroid Build Coastguard Worker 
451*c8dee2aaSAndroid Build Coastguard Worker         DrawQuad extra;
452*c8dee2aaSAndroid Build Coastguard Worker         int count = quad->fEdgeFlags != GrQuadAAFlags::kNone ? GrQuadUtils::ClipToW0(quad, &extra)
453*c8dee2aaSAndroid Build Coastguard Worker                                                              : 1;
454*c8dee2aaSAndroid Build Coastguard Worker         if (count == 0 ) {
455*c8dee2aaSAndroid Build Coastguard Worker             // Just skip the append (trivial success)
456*c8dee2aaSAndroid Build Coastguard Worker             return true;
457*c8dee2aaSAndroid Build Coastguard Worker         } else if (!this->canAddQuads(count, aaType)) {
458*c8dee2aaSAndroid Build Coastguard Worker             // Not enough room in the index buffer for the AA type
459*c8dee2aaSAndroid Build Coastguard Worker             return false;
460*c8dee2aaSAndroid Build Coastguard Worker         } else {
461*c8dee2aaSAndroid Build Coastguard Worker             // Can actually add the 1 or 2 quads representing the draw
462*c8dee2aaSAndroid Build Coastguard Worker             fQuads.append(quad->fDevice, { color, quad->fEdgeFlags },
463*c8dee2aaSAndroid Build Coastguard Worker                           fHelper.isTrivial() ? nullptr : &quad->fLocal);
464*c8dee2aaSAndroid Build Coastguard Worker             if (count > 1) {
465*c8dee2aaSAndroid Build Coastguard Worker                 fQuads.append(extra.fDevice, { color, extra.fEdgeFlags },
466*c8dee2aaSAndroid Build Coastguard Worker                               fHelper.isTrivial() ? nullptr : &extra.fLocal);
467*c8dee2aaSAndroid Build Coastguard Worker             }
468*c8dee2aaSAndroid Build Coastguard Worker             // Update the bounds
469*c8dee2aaSAndroid Build Coastguard Worker             this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
470*c8dee2aaSAndroid Build Coastguard Worker                             IsHairline::kNo);
471*c8dee2aaSAndroid Build Coastguard Worker             return true;
472*c8dee2aaSAndroid Build Coastguard Worker         }
473*c8dee2aaSAndroid Build Coastguard Worker     }
474*c8dee2aaSAndroid Build Coastguard Worker 
475*c8dee2aaSAndroid Build Coastguard Worker     struct ColorAndAA {
476*c8dee2aaSAndroid Build Coastguard Worker         SkPMColor4f fColor;
477*c8dee2aaSAndroid Build Coastguard Worker         GrQuadAAFlags fAAFlags;
478*c8dee2aaSAndroid Build Coastguard Worker     };
479*c8dee2aaSAndroid Build Coastguard Worker 
480*c8dee2aaSAndroid Build Coastguard Worker     Helper fHelper;
481*c8dee2aaSAndroid Build Coastguard Worker     GrQuadBuffer<ColorAndAA> fQuads;
482*c8dee2aaSAndroid Build Coastguard Worker     char* fPrePreparedVertices = nullptr;
483*c8dee2aaSAndroid Build Coastguard Worker 
484*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo* fProgramInfo = nullptr;
485*c8dee2aaSAndroid Build Coastguard Worker     ColorType      fColorType;
486*c8dee2aaSAndroid Build Coastguard Worker 
487*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fVertexBuffer;
488*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fIndexBuffer;
489*c8dee2aaSAndroid Build Coastguard Worker     int fBaseVertex;
490*c8dee2aaSAndroid Build Coastguard Worker 
491*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrMeshDrawOp;
492*c8dee2aaSAndroid Build Coastguard Worker };
493*c8dee2aaSAndroid Build Coastguard Worker 
494*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
495*c8dee2aaSAndroid Build Coastguard Worker 
496*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
497*c8dee2aaSAndroid Build Coastguard Worker 
Make(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,DrawQuad * quad,const GrUserStencilSettings * stencil,InputFlags inputFlags)498*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner FillRectOp::Make(GrRecordingContext* context,
499*c8dee2aaSAndroid Build Coastguard Worker                              GrPaint&& paint,
500*c8dee2aaSAndroid Build Coastguard Worker                              GrAAType aaType,
501*c8dee2aaSAndroid Build Coastguard Worker                              DrawQuad* quad,
502*c8dee2aaSAndroid Build Coastguard Worker                              const GrUserStencilSettings* stencil,
503*c8dee2aaSAndroid Build Coastguard Worker                              InputFlags inputFlags) {
504*c8dee2aaSAndroid Build Coastguard Worker     return FillRectOpImpl::Make(context, std::move(paint), aaType, std::move(quad), stencil,
505*c8dee2aaSAndroid Build Coastguard Worker                                 inputFlags);
506*c8dee2aaSAndroid Build Coastguard Worker }
507*c8dee2aaSAndroid Build Coastguard Worker 
MakeNonAARect(GrRecordingContext * context,GrPaint && paint,const SkMatrix & view,const SkRect & rect,const GrUserStencilSettings * stencil)508*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner FillRectOp::MakeNonAARect(GrRecordingContext* context,
509*c8dee2aaSAndroid Build Coastguard Worker                                       GrPaint&& paint,
510*c8dee2aaSAndroid Build Coastguard Worker                                       const SkMatrix& view,
511*c8dee2aaSAndroid Build Coastguard Worker                                       const SkRect& rect,
512*c8dee2aaSAndroid Build Coastguard Worker                                       const GrUserStencilSettings* stencil) {
513*c8dee2aaSAndroid Build Coastguard Worker     DrawQuad quad{GrQuad::MakeFromRect(rect, view), GrQuad(rect), GrQuadAAFlags::kNone};
514*c8dee2aaSAndroid Build Coastguard Worker     return FillRectOpImpl::Make(context, std::move(paint), GrAAType::kNone, &quad, stencil,
515*c8dee2aaSAndroid Build Coastguard Worker                                 InputFlags::kNone);
516*c8dee2aaSAndroid Build Coastguard Worker }
517*c8dee2aaSAndroid Build Coastguard Worker 
MakeOp(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const GrQuadSetEntry quads[],int cnt,const GrUserStencilSettings * stencilSettings,int * numConsumed)518*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner FillRectOp::MakeOp(GrRecordingContext* context,
519*c8dee2aaSAndroid Build Coastguard Worker                                GrPaint&& paint,
520*c8dee2aaSAndroid Build Coastguard Worker                                GrAAType aaType,
521*c8dee2aaSAndroid Build Coastguard Worker                                const SkMatrix& viewMatrix,
522*c8dee2aaSAndroid Build Coastguard Worker                                const GrQuadSetEntry quads[],
523*c8dee2aaSAndroid Build Coastguard Worker                                int cnt,
524*c8dee2aaSAndroid Build Coastguard Worker                                const GrUserStencilSettings* stencilSettings,
525*c8dee2aaSAndroid Build Coastguard Worker                                int* numConsumed) {
526*c8dee2aaSAndroid Build Coastguard Worker     // First make a draw op for the first quad in the set
527*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(cnt > 0);
528*c8dee2aaSAndroid Build Coastguard Worker 
529*c8dee2aaSAndroid Build Coastguard Worker     DrawQuad quad{GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
530*c8dee2aaSAndroid Build Coastguard Worker                   GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix),
531*c8dee2aaSAndroid Build Coastguard Worker                   quads[0].fAAFlags};
532*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor4f(quads[0].fColor);
533*c8dee2aaSAndroid Build Coastguard Worker     GrOp::Owner op = FillRectOp::Make(context, std::move(paint), aaType,
534*c8dee2aaSAndroid Build Coastguard Worker                                       &quad, stencilSettings, InputFlags::kNone);
535*c8dee2aaSAndroid Build Coastguard Worker     auto fillRects = op->cast<FillRectOpImpl>();
536*c8dee2aaSAndroid Build Coastguard Worker 
537*c8dee2aaSAndroid Build Coastguard Worker     *numConsumed = 1;
538*c8dee2aaSAndroid Build Coastguard Worker     // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
539*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 1; i < cnt; ++i) {
540*c8dee2aaSAndroid Build Coastguard Worker         quad = {GrQuad::MakeFromRect(quads[i].fRect, viewMatrix),
541*c8dee2aaSAndroid Build Coastguard Worker                 GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
542*c8dee2aaSAndroid Build Coastguard Worker                 quads[i].fAAFlags};
543*c8dee2aaSAndroid Build Coastguard Worker 
544*c8dee2aaSAndroid Build Coastguard Worker         GrAAType resolvedAA;
545*c8dee2aaSAndroid Build Coastguard Worker         GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, quad.fDevice,
546*c8dee2aaSAndroid Build Coastguard Worker                                    &resolvedAA, &quad.fEdgeFlags);
547*c8dee2aaSAndroid Build Coastguard Worker 
548*c8dee2aaSAndroid Build Coastguard Worker         if (!fillRects->addQuad(&quad, quads[i].fColor, resolvedAA)) {
549*c8dee2aaSAndroid Build Coastguard Worker             break;
550*c8dee2aaSAndroid Build Coastguard Worker         }
551*c8dee2aaSAndroid Build Coastguard Worker 
552*c8dee2aaSAndroid Build Coastguard Worker         (*numConsumed)++;
553*c8dee2aaSAndroid Build Coastguard Worker     }
554*c8dee2aaSAndroid Build Coastguard Worker 
555*c8dee2aaSAndroid Build Coastguard Worker     return op;
556*c8dee2aaSAndroid Build Coastguard Worker }
557*c8dee2aaSAndroid Build Coastguard Worker 
AddFillRectOps(skgpu::ganesh::SurfaceDrawContext * sdc,const GrClip * clip,GrRecordingContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const GrQuadSetEntry quads[],int cnt,const GrUserStencilSettings * stencilSettings)558*c8dee2aaSAndroid Build Coastguard Worker void FillRectOp::AddFillRectOps(skgpu::ganesh::SurfaceDrawContext* sdc,
559*c8dee2aaSAndroid Build Coastguard Worker                                 const GrClip* clip,
560*c8dee2aaSAndroid Build Coastguard Worker                                 GrRecordingContext* context,
561*c8dee2aaSAndroid Build Coastguard Worker                                 GrPaint&& paint,
562*c8dee2aaSAndroid Build Coastguard Worker                                 GrAAType aaType,
563*c8dee2aaSAndroid Build Coastguard Worker                                 const SkMatrix& viewMatrix,
564*c8dee2aaSAndroid Build Coastguard Worker                                 const GrQuadSetEntry quads[],
565*c8dee2aaSAndroid Build Coastguard Worker                                 int cnt,
566*c8dee2aaSAndroid Build Coastguard Worker                                 const GrUserStencilSettings* stencilSettings) {
567*c8dee2aaSAndroid Build Coastguard Worker     int offset = 0;
568*c8dee2aaSAndroid Build Coastguard Worker     int numLeft = cnt;
569*c8dee2aaSAndroid Build Coastguard Worker     while (numLeft) {
570*c8dee2aaSAndroid Build Coastguard Worker         int numConsumed = 0;
571*c8dee2aaSAndroid Build Coastguard Worker 
572*c8dee2aaSAndroid Build Coastguard Worker         GrOp::Owner op = MakeOp(context, GrPaint::Clone(paint), aaType, viewMatrix,
573*c8dee2aaSAndroid Build Coastguard Worker                                 &quads[offset], numLeft, stencilSettings,
574*c8dee2aaSAndroid Build Coastguard Worker                                 &numConsumed);
575*c8dee2aaSAndroid Build Coastguard Worker 
576*c8dee2aaSAndroid Build Coastguard Worker         offset += numConsumed;
577*c8dee2aaSAndroid Build Coastguard Worker         numLeft -= numConsumed;
578*c8dee2aaSAndroid Build Coastguard Worker 
579*c8dee2aaSAndroid Build Coastguard Worker         sdc->addDrawOp(clip, std::move(op));
580*c8dee2aaSAndroid Build Coastguard Worker     }
581*c8dee2aaSAndroid Build Coastguard Worker 
582*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(offset == cnt);
583*c8dee2aaSAndroid Build Coastguard Worker }
584*c8dee2aaSAndroid Build Coastguard Worker 
585*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::ganesh
586*c8dee2aaSAndroid Build Coastguard Worker 
587*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
588*c8dee2aaSAndroid Build Coastguard Worker 
ClassID()589*c8dee2aaSAndroid Build Coastguard Worker uint32_t skgpu::ganesh::FillRectOp::ClassID() { return FillRectOpImpl::ClassID(); }
590*c8dee2aaSAndroid Build Coastguard Worker 
GR_DRAW_OP_TEST_DEFINE(FillRectOp)591*c8dee2aaSAndroid Build Coastguard Worker GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
592*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
593*c8dee2aaSAndroid Build Coastguard Worker     SkRect rect = GrTest::TestRect(random);
594*c8dee2aaSAndroid Build Coastguard Worker 
595*c8dee2aaSAndroid Build Coastguard Worker     GrAAType aaType = GrAAType::kNone;
596*c8dee2aaSAndroid Build Coastguard Worker     if (random->nextBool()) {
597*c8dee2aaSAndroid Build Coastguard Worker         aaType = (numSamples > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
598*c8dee2aaSAndroid Build Coastguard Worker     }
599*c8dee2aaSAndroid Build Coastguard Worker     const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
600*c8dee2aaSAndroid Build Coastguard Worker                                                               : GrGetRandomStencil(random, context);
601*c8dee2aaSAndroid Build Coastguard Worker 
602*c8dee2aaSAndroid Build Coastguard Worker     GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
603*c8dee2aaSAndroid Build Coastguard Worker     aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
604*c8dee2aaSAndroid Build Coastguard Worker     aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
605*c8dee2aaSAndroid Build Coastguard Worker     aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
606*c8dee2aaSAndroid Build Coastguard Worker     aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
607*c8dee2aaSAndroid Build Coastguard Worker 
608*c8dee2aaSAndroid Build Coastguard Worker     if (random->nextBool()) {
609*c8dee2aaSAndroid Build Coastguard Worker         if (random->nextBool()) {
610*c8dee2aaSAndroid Build Coastguard Worker             // Single local matrix
611*c8dee2aaSAndroid Build Coastguard Worker             SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
612*c8dee2aaSAndroid Build Coastguard Worker             DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix),
613*c8dee2aaSAndroid Build Coastguard Worker                              GrQuad::MakeFromRect(rect, localMatrix), aaFlags};
614*c8dee2aaSAndroid Build Coastguard Worker             return skgpu::ganesh::FillRectOp::Make(
615*c8dee2aaSAndroid Build Coastguard Worker                     context, std::move(paint), aaType, &quad, stencil);
616*c8dee2aaSAndroid Build Coastguard Worker         } else {
617*c8dee2aaSAndroid Build Coastguard Worker             // Pass local rect directly
618*c8dee2aaSAndroid Build Coastguard Worker             SkRect localRect = GrTest::TestRect(random);
619*c8dee2aaSAndroid Build Coastguard Worker             DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix),
620*c8dee2aaSAndroid Build Coastguard Worker                              GrQuad(localRect), aaFlags};
621*c8dee2aaSAndroid Build Coastguard Worker             return skgpu::ganesh::FillRectOp::Make(
622*c8dee2aaSAndroid Build Coastguard Worker                     context, std::move(paint), aaType, &quad, stencil);
623*c8dee2aaSAndroid Build Coastguard Worker         }
624*c8dee2aaSAndroid Build Coastguard Worker     } else {
625*c8dee2aaSAndroid Build Coastguard Worker         // The simplest constructor
626*c8dee2aaSAndroid Build Coastguard Worker         DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(rect), aaFlags};
627*c8dee2aaSAndroid Build Coastguard Worker         return skgpu::ganesh::FillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
628*c8dee2aaSAndroid Build Coastguard Worker     }
629*c8dee2aaSAndroid Build Coastguard Worker }
630*c8dee2aaSAndroid Build Coastguard Worker 
631*c8dee2aaSAndroid Build Coastguard Worker #endif
632