1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GrFillRectOp.h"
9 
10 #include "GrCaps.h"
11 #include "GrGeometryProcessor.h"
12 #include "GrMeshDrawOp.h"
13 #include "GrPaint.h"
14 #include "GrQuad.h"
15 #include "GrQuadPerEdgeAA.h"
16 #include "GrSimpleMeshDrawOpHelper.h"
17 #include "SkMatrix.h"
18 #include "SkRect.h"
19 #include "glsl/GrGLSLColorSpaceXformHelper.h"
20 #include "glsl/GrGLSLGeometryProcessor.h"
21 #include "glsl/GrGLSLVarying.h"
22 
23 namespace {
24 
25 using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
26 using ColorType = GrQuadPerEdgeAA::ColorType;
27 
28 #ifdef SK_DEBUG
dump_quad_info(int index,const GrPerspQuad & deviceQuad,const GrPerspQuad & localQuad,const SkPMColor4f & color,GrQuadAAFlags aaFlags)29 static SkString dump_quad_info(int index, const GrPerspQuad& deviceQuad,
30                                const GrPerspQuad& localQuad, const SkPMColor4f& color,
31                                GrQuadAAFlags aaFlags) {
32     SkString str;
33     str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
34                 "  device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
35                 "(%.2f, %.2f, %.2f)],\n"
36                 "  local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
37                 "(%.2f, %.2f, %.2f)]\n",
38                 index, color.fR, color.fG, color.fB, color.fA,
39                 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
40                 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
41                 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
42                 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
43                 deviceQuad.x(0), deviceQuad.y(0), deviceQuad.w(0),
44                 deviceQuad.x(1), deviceQuad.y(1), deviceQuad.w(1),
45                 deviceQuad.x(2), deviceQuad.y(2), deviceQuad.w(2),
46                 deviceQuad.x(3), deviceQuad.y(3), deviceQuad.w(3),
47                 localQuad.x(0), localQuad.y(0), localQuad.w(0),
48                 localQuad.x(1), localQuad.y(1), localQuad.w(1),
49                 localQuad.x(2), localQuad.y(2), localQuad.w(2),
50                 localQuad.x(3), localQuad.y(3), localQuad.w(3));
51     return str;
52 }
53 #endif
54 
55 class FillRectOp final : public GrMeshDrawOp {
56 private:
57     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
58 
59 public:
Make(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,GrQuadAAFlags edgeAA,const GrUserStencilSettings * stencilSettings,const GrPerspQuad & deviceQuad,GrQuadType deviceQuadType,const GrPerspQuad & localQuad,GrQuadType localQuadType)60     static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
61                                           GrPaint&& paint,
62                                           GrAAType aaType,
63                                           GrQuadAAFlags edgeAA,
64                                           const GrUserStencilSettings* stencilSettings,
65                                           const GrPerspQuad& deviceQuad,
66                                           GrQuadType deviceQuadType,
67                                           const GrPerspQuad& localQuad,
68                                           GrQuadType localQuadType) {
69         // Clean up deviations between aaType and edgeAA
70         GrResolveAATypeForQuad(aaType, edgeAA, deviceQuad, deviceQuadType, &aaType, &edgeAA);
71         return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
72                 stencilSettings, deviceQuad, deviceQuadType, localQuad, localQuadType);
73     }
74 
75     // aaType is passed to Helper in the initializer list, so incongruities between aaType and
76     // edgeFlags must be resolved prior to calling this constructor.
FillRectOp(Helper::MakeArgs args,SkPMColor4f paintColor,GrAAType aaType,GrQuadAAFlags edgeFlags,const GrUserStencilSettings * stencil,const GrPerspQuad & deviceQuad,GrQuadType deviceQuadType,const GrPerspQuad & localQuad,GrQuadType localQuadType)77     FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
78                GrQuadAAFlags edgeFlags, const GrUserStencilSettings* stencil,
79                const GrPerspQuad& deviceQuad, GrQuadType deviceQuadType,
80                const GrPerspQuad& localQuad, GrQuadType localQuadType)
81             : INHERITED(ClassID())
82             , fHelper(args, aaType, stencil)
83             , fColorType(GrQuadPerEdgeAA::MinColorType(paintColor)) {
84         // The color stored with the quad is the clear color if a scissor-clear is decided upon
85         // when executing the op.
86         fDeviceQuads.push_back(deviceQuad, deviceQuadType, { paintColor, edgeFlags });
87 
88         if (!fHelper.isTrivial()) {
89             // Conservatively keep track of the local coordinates; it may be that the paint doesn't
90             // need them after analysis is finished. If the paint is known to be solid up front they
91             // can be skipped entirely.
92             fLocalQuads.push_back(localQuad, localQuadType);
93         }
94         this->setBounds(deviceQuad.bounds(deviceQuadType),
95                         HasAABloat(aaType == GrAAType::kCoverage), IsZeroArea::kNo);
96     }
97 
name() const98     const char* name() const override { return "FillRectOp"; }
99 
visitProxies(const VisitProxyFunc & func,VisitorType) const100     void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
101         return fHelper.visitProxies(func);
102     }
103 
104 #ifdef SK_DEBUG
dumpInfo() const105     SkString dumpInfo() const override {
106         SkString str;
107         str.appendf("# draws: %u\n", this->quadCount());
108         str.appendf("Device quad type: %u, local quad type: %u\n",
109                     (uint32_t) fDeviceQuads.quadType(), (uint32_t) fLocalQuads.quadType());
110         str += fHelper.dumpInfo();
111         GrPerspQuad device, local;
112         for (int i = 0; i < this->quadCount(); i++) {
113             device = fDeviceQuads[i];
114             const ColorAndAA& info = fDeviceQuads.metadata(i);
115             if (!fHelper.isTrivial()) {
116                 local = fLocalQuads[i];
117             }
118             str += dump_quad_info(i, device, local, info.fColor, info.fAAFlags);
119         }
120         str += INHERITED::dumpInfo();
121         return str;
122     }
123 #endif
124 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrFSAAType fsaaType,GrClampType clampType)125     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
126                                       GrFSAAType fsaaType, GrClampType clampType) override {
127         // Initialize aggregate color analysis with the first quad's color (which always exists)
128         SkASSERT(this->quadCount() > 0);
129         GrProcessorAnalysisColor quadColors(fDeviceQuads.metadata(0).fColor);
130         // Then combine the colors of any additional quads (e.g. from MakeSet)
131         for (int i = 1; i < this->quadCount(); ++i) {
132             quadColors = GrProcessorAnalysisColor::Combine(quadColors,
133                                                            fDeviceQuads.metadata(i).fColor);
134             if (quadColors.isUnknown()) {
135                 // No point in accumulating additional starting colors, combining cannot make it
136                 // less unknown.
137                 break;
138             }
139         }
140 
141         // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
142         // then the coverage is always 1.0, so specify kNone for more optimal blending.
143         GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
144                 GrProcessorAnalysisCoverage::kSingleChannel :
145                 GrProcessorAnalysisCoverage::kNone;
146         auto result = fHelper.finalizeProcessors(
147                 caps, clip, fsaaType, clampType, coverage, &quadColors);
148         // If there is a constant color after analysis, that means all of the quads should be set
149         // to the same color (even if they started out with different colors).
150         SkPMColor4f colorOverride;
151         if (quadColors.isConstant(&colorOverride)) {
152             // TODO: Unified strategy for handling wide color outputs from processor analysis.
153             // skbug.com/8871
154             fColorType = GrQuadPerEdgeAA::MinColorType(colorOverride);
155             if (fColorType == ColorType::kHalf && !caps.halfFloatVertexAttributeSupport()) {
156                 fColorType = ColorType::kByte;
157                 colorOverride = {SkTPin(colorOverride.fR, 0.0f, 1.0f),
158                                  SkTPin(colorOverride.fG, 0.0f, 1.0f),
159                                  SkTPin(colorOverride.fB, 0.0f, 1.0f),
160                                  colorOverride.fA};
161             }
162             for (int i = 0; i < this->quadCount(); ++i) {
163                 fDeviceQuads.metadata(i).fColor = colorOverride;
164             }
165         }
166         // Most SkShaders' FPs multiply their calculated color by the paint color or alpha. We want
167         // to use ColorType::kNone to optimize out that multiply. However, if there are no color
168         // FPs then were really writing a special shader for white rectangles and not saving any
169         // multiples. So in that case use bytes to avoid the extra shader (and possibly work around
170         // an ANGLE issue: crbug.com/942565).
171         if (fColorType == ColorType::kNone && !result.hasColorFragmentProcessor()) {
172             fColorType = ColorType::kByte;
173         }
174 
175         return result;
176     }
177 
fixedFunctionFlags() const178     FixedFunctionFlags fixedFunctionFlags() const override {
179         // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
180         // the helper's fixed function flags are appropriate.
181         return fHelper.fixedFunctionFlags();
182     }
183 
184     DEFINE_OP_CLASS_ID
185 
186 private:
187     // For GrFillRectOp::MakeSet's use of addQuad
188     friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(
189             GrRecordingContext*,
190             GrPaint&&,
191             GrAAType, const SkMatrix& viewMatrix,
192             const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
193             const GrUserStencilSettings*);
194 
onPrepareDraws(Target * target)195     void onPrepareDraws(Target* target) override {
196         TRACE_EVENT0("skia", TRACE_FUNC);
197 
198         using Domain = GrQuadPerEdgeAA::Domain;
199         static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
200 
201         VertexSpec vertexSpec(fDeviceQuads.quadType(), fColorType, fLocalQuads.quadType(),
202                               fHelper.usesLocalCoords(), Domain::kNo, fHelper.aaType(),
203                               fHelper.compatibleWithAlphaAsCoverage());
204         // Make sure that if the op thought it was a solid color, the vertex spec does not use
205         // local coords.
206         SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
207 
208         sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
209         size_t vertexSize = gp->vertexStride();
210 
211         sk_sp<const GrBuffer> vbuffer;
212         int vertexOffsetInBuffer = 0;
213 
214         // Fill the allocated vertex data
215         void* vdata = target->makeVertexSpace(
216                 vertexSize, this->quadCount() * vertexSpec.verticesPerQuad(),
217                 &vbuffer, &vertexOffsetInBuffer);
218         if (!vdata) {
219             SkDebugf("Could not allocate vertices\n");
220             return;
221         }
222 
223         // vertices pointer advances through vdata based on Tessellate's return value
224         void* vertices = vdata;
225         if (fHelper.isTrivial()) {
226             SkASSERT(fLocalQuads.count() == 0); // No local coords, so send an ignored dummy quad
227             static const GrPerspQuad kIgnoredLocal(SkRect::MakeEmpty());
228 
229             for (int i = 0; i < this->quadCount(); ++i) {
230                 const ColorAndAA& info = fDeviceQuads.metadata(i);
231                 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
232                         info.fColor, kIgnoredLocal, kEmptyDomain, info.fAAFlags);
233             }
234         } else {
235             SkASSERT(fLocalQuads.count() == fDeviceQuads.count());
236             for (int i = 0; i < this->quadCount(); ++i) {
237                 const ColorAndAA& info = fDeviceQuads.metadata(i);
238                 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
239                         info.fColor, fLocalQuads[i], kEmptyDomain, info.fAAFlags);
240             }
241         }
242 
243         // Configure the mesh for the vertex data
244         GrMesh* mesh = target->allocMeshes(1);
245         if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, this->quadCount())) {
246             SkDebugf("Could not allocate indices\n");
247             return;
248         }
249         mesh->setVertexData(std::move(vbuffer), vertexOffsetInBuffer);
250         target->recordDraw(std::move(gp), mesh);
251     }
252 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)253     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
254         fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
255     }
256 
onCombineIfPossible(GrOp * t,const GrCaps & caps)257     CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
258         TRACE_EVENT0("skia", TRACE_FUNC);
259         const auto* that = t->cast<FillRectOp>();
260 
261         if ((fHelper.aaType() == GrAAType::kCoverage ||
262              that->fHelper.aaType() == GrAAType::kCoverage) &&
263             this->quadCount() + that->quadCount() > GrQuadPerEdgeAA::kNumAAQuadsInIndexBuffer) {
264             // This limit on batch size seems to help on Adreno devices
265             return CombineResult::kCannotCombine;
266         }
267 
268         // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
269         // ops together, so pass true as the last argument.
270         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
271             return CombineResult::kCannotCombine;
272         }
273 
274         // If the paints were compatible, the trivial/solid-color state should be the same
275         SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
276 
277         // If the processor sets are compatible, the two ops are always compatible; it just needs to
278         // adjust the state of the op to be the more general quad and aa types of the two ops and
279         // then concatenate the per-quad data.
280         fColorType = SkTMax(fColorType, that->fColorType);
281 
282         // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
283         // types to be none and coverage, in which case this op's aa type must be lifted to coverage
284         // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
285         if (fHelper.aaType() == GrAAType::kNone && that->fHelper.aaType() == GrAAType::kCoverage) {
286             fHelper.setAAType(GrAAType::kCoverage);
287         }
288 
289         fDeviceQuads.concat(that->fDeviceQuads);
290         if (!fHelper.isTrivial()) {
291             fLocalQuads.concat(that->fLocalQuads);
292         }
293         return CombineResult::kMerged;
294     }
295 
296     // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
297     // But since it's avoiding the op list management, it must update the op's bounds. This is only
298     // used with quad sets, which uses the same view matrix for each quad so this assumes that the
299     // device quad type of the new quad is the same as the op's.
addQuad(const GrPerspQuad & deviceQuad,const GrPerspQuad & localQuad,GrQuadType localQuadType,const SkPMColor4f & color,GrQuadAAFlags edgeAA,GrAAType aaType)300     void addQuad(const GrPerspQuad& deviceQuad, const GrPerspQuad& localQuad,
301                  GrQuadType localQuadType, const SkPMColor4f& color, GrQuadAAFlags edgeAA,
302                  GrAAType aaType) {
303         SkASSERT(deviceQuad.quadType() <= fDeviceQuads.quadType());
304 
305         // The new quad's aa type should be the same as the first quad's or none, except when the
306         // first quad's aa type was already downgraded to none, in which case the stored type must
307         // be lifted to back to the requested type.
308         if (aaType != fHelper.aaType()) {
309             if (aaType != GrAAType::kNone) {
310                 // Original quad was downgraded to non-aa, lift back up to this quad's required type
311                 SkASSERT(fHelper.aaType() == GrAAType::kNone);
312                 fHelper.setAAType(aaType);
313             }
314             // else the new quad could have been downgraded but the other quads can't be, so don't
315             // reset the op's accumulated aa type.
316         }
317 
318         // clear compatible won't need to be updated, since device quad type and paint is the same,
319         // but this quad has a new color, so maybe update color type
320         fColorType = SkTMax(fColorType, GrQuadPerEdgeAA::MinColorType(color));
321 
322         // Update the bounds and add the quad to this op's storage
323         SkRect newBounds = this->bounds();
324         newBounds.joinPossiblyEmptyRect(deviceQuad.bounds(fDeviceQuads.quadType()));
325         this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
326                         IsZeroArea::kNo);
327         fDeviceQuads.push_back(deviceQuad, fDeviceQuads.quadType(), { color, edgeAA });
328         if (!fHelper.isTrivial()) {
329             fLocalQuads.push_back(localQuad, localQuadType);
330         }
331     }
332 
quadCount() const333     int quadCount() const {
334         // Sanity check that the parallel arrays for quad properties all have the same size
335         SkASSERT(fDeviceQuads.count() == fLocalQuads.count() ||
336                  (fLocalQuads.count() == 0 && fHelper.isTrivial()));
337         return fDeviceQuads.count();
338     }
339 
340     struct ColorAndAA {
341         SkPMColor4f fColor;
342         GrQuadAAFlags fAAFlags;
343     };
344 
345     Helper fHelper;
346     GrTQuadList<ColorAndAA> fDeviceQuads;
347     // No metadata attached to the local quads; this list is empty when local coords are not needed.
348     GrQuadList fLocalQuads;
349 
350     ColorType fColorType;
351 
352     typedef GrMeshDrawOp INHERITED;
353 };
354 
355 } // anonymous namespace
356 
357 namespace GrFillRectOp {
358 
MakePerEdge(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkRect & rect,const GrUserStencilSettings * stencilSettings)359 std::unique_ptr<GrDrawOp> MakePerEdge(GrRecordingContext* context,
360                                       GrPaint&& paint,
361                                       GrAAType aaType,
362                                       GrQuadAAFlags edgeAA,
363                                       const SkMatrix& viewMatrix,
364                                       const SkRect& rect,
365                                       const GrUserStencilSettings* stencilSettings) {
366     GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
367     return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
368                             GrPerspQuad::MakeFromRect(rect, viewMatrix),  dstQuadType,
369                             GrPerspQuad(rect), GrQuadType::kRect);
370 }
371 
MakePerEdgeWithLocalMatrix(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect,const GrUserStencilSettings * stencilSettings)372 std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrRecordingContext* context,
373                                                      GrPaint&& paint,
374                                                      GrAAType aaType,
375                                                      GrQuadAAFlags edgeAA,
376                                                      const SkMatrix& viewMatrix,
377                                                      const SkMatrix& localMatrix,
378                                                      const SkRect& rect,
379                                                      const GrUserStencilSettings* stencilSettings) {
380     GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
381     GrQuadType localQuadType = GrQuadTypeForTransformedRect(localMatrix);
382     return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
383                             GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
384                             GrPerspQuad::MakeFromRect(rect, localMatrix), localQuadType);
385 }
386 
MakePerEdgeWithLocalRect(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & localRect,const GrUserStencilSettings * stencilSettings)387 std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrRecordingContext* context,
388                                                    GrPaint&& paint,
389                                                    GrAAType aaType,
390                                                    GrQuadAAFlags edgeAA,
391                                                    const SkMatrix& viewMatrix,
392                                                    const SkRect& rect,
393                                                    const SkRect& localRect,
394                                                    const GrUserStencilSettings* stencilSettings) {
395     GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
396     return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
397                             GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
398                             GrPerspQuad(localRect), GrQuadType::kRect);
399 }
400 
MakePerEdgeQuad(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkPoint quad[4],const SkPoint localQuad[4],const GrUserStencilSettings * stencilSettings)401 std::unique_ptr<GrDrawOp> MakePerEdgeQuad(GrRecordingContext* context,
402                                           GrPaint&& paint,
403                                           GrAAType aaType,
404                                           GrQuadAAFlags edgeAA,
405                                           const SkMatrix& viewMatrix,
406                                           const SkPoint quad[4],
407                                           const SkPoint localQuad[4],
408                                           const GrUserStencilSettings* stencilSettings) {
409     // With arbitrary quads, the quad types are limited to kStandard or kPerspective (unless we
410     // analyzed the points, but callers have more knowledge and should've just use the appropriate
411     // factory, so assume they can't be rectilinear or simpler)
412     GrQuadType deviceType = viewMatrix.hasPerspective() ? GrQuadType::kPerspective
413                                                         : GrQuadType::kStandard;
414     return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
415                             GrPerspQuad::MakeFromSkQuad(quad, viewMatrix), deviceType,
416                             GrPerspQuad::MakeFromSkQuad(localQuad ? localQuad : quad,
417                                                         SkMatrix::I()), GrQuadType::kStandard);
418 }
419 
MakeSet(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const GrRenderTargetContext::QuadSetEntry quads[],int cnt,const GrUserStencilSettings * stencilSettings)420 std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
421                                   GrPaint&& paint,
422                                   GrAAType aaType,
423                                   const SkMatrix& viewMatrix,
424                                   const GrRenderTargetContext::QuadSetEntry quads[],
425                                   int cnt,
426                                   const GrUserStencilSettings* stencilSettings) {
427     // First make a draw op for the first quad in the set
428     SkASSERT(cnt > 0);
429     GrQuadType deviceQuadType = GrQuadTypeForTransformedRect(viewMatrix);
430 
431     paint.setColor4f(quads[0].fColor);
432     std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
433             quads[0].fAAFlags, stencilSettings,
434             GrPerspQuad::MakeFromRect(quads[0].fRect, viewMatrix), deviceQuadType,
435             GrPerspQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix),
436             GrQuadTypeForTransformedRect(quads[0].fLocalMatrix));
437     auto* fillRects = op->cast<FillRectOp>();
438 
439     // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
440     for (int i = 1; i < cnt; ++i) {
441         GrPerspQuad deviceQuad = GrPerspQuad::MakeFromRect(quads[i].fRect, viewMatrix);
442 
443         GrAAType resolvedAA;
444         GrQuadAAFlags resolvedEdgeFlags;
445         GrResolveAATypeForQuad(aaType, quads[i].fAAFlags, deviceQuad, deviceQuadType,
446                                &resolvedAA, &resolvedEdgeFlags);
447 
448         fillRects->addQuad(deviceQuad,
449                            GrPerspQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
450                            GrQuadTypeForTransformedRect(quads[i].fLocalMatrix), quads[i].fColor,
451                            resolvedEdgeFlags,resolvedAA);
452     }
453 
454     return op;
455 }
456 
Make(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & rect,const GrUserStencilSettings * stencil)457 std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
458                                GrPaint&& paint,
459                                GrAAType aaType,
460                                const SkMatrix& viewMatrix,
461                                const SkRect& rect,
462                                const GrUserStencilSettings* stencil) {
463     return MakePerEdge(context, std::move(paint), aaType,
464             aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
465             viewMatrix, rect, stencil);
466 }
467 
MakeWithLocalMatrix(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect,const GrUserStencilSettings * stencil)468 std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrRecordingContext* context,
469                                               GrPaint&& paint,
470                                               GrAAType aaType,
471                                               const SkMatrix& viewMatrix,
472                                               const SkMatrix& localMatrix,
473                                               const SkRect& rect,
474                                               const GrUserStencilSettings* stencil) {
475     return MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
476             aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
477             viewMatrix, localMatrix, rect, stencil);
478 }
479 
MakeWithLocalRect(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & localRect,const GrUserStencilSettings * stencil)480 std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrRecordingContext* context,
481                                             GrPaint&& paint,
482                                             GrAAType aaType,
483                                             const SkMatrix& viewMatrix,
484                                             const SkRect& rect,
485                                             const SkRect& localRect,
486                                             const GrUserStencilSettings* stencil) {
487     return MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
488             aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
489             viewMatrix, rect, localRect, stencil);
490 }
491 
492 } // namespace GrFillRectOp
493 
494 #if GR_TEST_UTILS
495 
496 #include "GrDrawOpTest.h"
497 #include "SkGr.h"
498 
GR_DRAW_OP_TEST_DEFINE(FillRectOp)499 GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
500     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
501     SkRect rect = GrTest::TestRect(random);
502 
503     GrAAType aaType = GrAAType::kNone;
504     if (random->nextBool()) {
505         aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
506     }
507     const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
508                                                               : GrGetRandomStencil(random, context);
509 
510     GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
511     aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
512     aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
513     aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
514     aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
515 
516     if (random->nextBool()) {
517         if (random->nextBool()) {
518             if (random->nextBool()) {
519                 // Local matrix with a set op
520                 uint32_t extraQuadCt = random->nextRangeU(1, 4);
521                 SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
522                 quads.push_back(
523                         {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
524                          GrTest::TestMatrixInvertible(random), aaFlags});
525                 for (uint32_t i = 0; i < extraQuadCt; ++i) {
526                     GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
527                     aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
528                     aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
529                     aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
530                     aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
531 
532                     quads.push_back(
533                         {GrTest::TestRect(random),
534                          SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
535                          GrTest::TestMatrixInvertible(random), aaFlags});
536                 }
537 
538                 return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
539                                              quads.begin(), quads.count(), stencil);
540             } else {
541                 // Single local matrix
542                 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
543                 return GrFillRectOp::MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
544                                                                 aaFlags, viewMatrix, localMatrix,
545                                                                 rect, stencil);
546             }
547         } else {
548             // Pass local rect directly
549             SkRect localRect = GrTest::TestRect(random);
550             return GrFillRectOp::MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
551                                                           aaFlags, viewMatrix, rect, localRect,
552                                                           stencil);
553         }
554     } else {
555         // The simplest constructor
556         return GrFillRectOp::MakePerEdge(context, std::move(paint), aaType, aaFlags, viewMatrix,
557                                          rect, stencil);
558     }
559 }
560 
561 #endif
562