blob: 8efbcbd427b6d633c52672b0c0627ee6f0516204 [file] [log] [blame]
Michael Ludwig69858532018-11-28 15:34:34 -05001/*
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 "GrGeometryProcessor.h"
11#include "GrMeshDrawOp.h"
12#include "GrPaint.h"
13#include "GrQuad.h"
14#include "GrQuadPerEdgeAA.h"
15#include "GrSimpleMeshDrawOpHelper.h"
16#include "SkMatrix.h"
17#include "SkRect.h"
18#include "glsl/GrGLSLColorSpaceXformHelper.h"
19#include "glsl/GrGLSLGeometryProcessor.h"
20#include "glsl/GrGLSLVarying.h"
21
22namespace {
23
24using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
25using ColorType = GrQuadPerEdgeAA::ColorType;
26
27// NOTE: This info structure is intentionally modeled after GrTextureOps' Quad so that they can
28// more easily be integrated together in the future.
29class TransformedQuad {
30public:
31 TransformedQuad(const GrPerspQuad& deviceQuad, const GrPerspQuad& localQuad,
32 const SkPMColor4f& color, GrQuadAAFlags aaFlags)
33 : fDeviceQuad(deviceQuad)
34 , fLocalQuad(localQuad)
35 , fColor(color)
36 , fAAFlags(aaFlags) {}
37
38 const GrPerspQuad& deviceQuad() const { return fDeviceQuad; }
39 const GrPerspQuad& localQuad() const { return fLocalQuad; }
40 const SkPMColor4f& color() const { return fColor; }
41 GrQuadAAFlags aaFlags() const { return fAAFlags; }
42
43 void setColor(const SkPMColor4f& color) { fColor = color; }
44
45 SkString dumpInfo(int index) const {
46 SkString str;
47 str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
48 " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
49 "(%.2f, %.2f, %.2f)],\n"
50 " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
51 "(%.2f, %.2f, %.2f)]\n",
52 index, fColor.fR, fColor.fG, fColor.fB, fColor.fA,
53 (uint32_t) (fAAFlags & GrQuadAAFlags::kLeft),
54 (uint32_t) (fAAFlags & GrQuadAAFlags::kTop),
55 (uint32_t) (fAAFlags & GrQuadAAFlags::kRight),
56 (uint32_t) (fAAFlags & GrQuadAAFlags::kBottom),
57 fDeviceQuad.x(0), fDeviceQuad.y(0), fDeviceQuad.w(0),
58 fDeviceQuad.x(1), fDeviceQuad.y(1), fDeviceQuad.w(1),
59 fDeviceQuad.x(2), fDeviceQuad.y(2), fDeviceQuad.w(2),
60 fDeviceQuad.x(3), fDeviceQuad.y(3), fDeviceQuad.w(3),
61 fLocalQuad.x(0), fLocalQuad.y(0), fLocalQuad.w(0),
62 fLocalQuad.x(1), fLocalQuad.y(1), fLocalQuad.w(1),
63 fLocalQuad.x(2), fLocalQuad.y(2), fLocalQuad.w(2),
64 fLocalQuad.x(3), fLocalQuad.y(3), fLocalQuad.w(3));
65 return str;
66 }
67private:
68 // NOTE: The TransformedQuad does not store the types for device and local. The owning op tracks
69 // the most general type for device and local across all of its merged quads.
70 GrPerspQuad fDeviceQuad; // In device space, allowing rects to be combined across view matrices
71 GrPerspQuad fLocalQuad; // Original rect transformed by its local matrix
72 SkPMColor4f fColor;
73 GrQuadAAFlags fAAFlags;
74};
75
Michael Ludwig69858532018-11-28 15:34:34 -050076class FillRectOp final : public GrMeshDrawOp {
77private:
78 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
79
80public:
81 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
82 GrPaint&& paint,
83 GrAAType aaType,
84 GrQuadAAFlags edgeAA,
85 const GrUserStencilSettings* stencilSettings,
86 const GrPerspQuad& deviceQuad,
87 GrQuadType deviceQuadType,
88 const GrPerspQuad& localQuad,
89 GrQuadType localQuadType) {
90 // Clean up deviations between aaType and edgeAA
91 GrResolveAATypeForQuad(aaType, edgeAA, deviceQuad, deviceQuadType, &aaType, &edgeAA);
92
93 // Analyze the paint to see if it is compatible with scissor-clearing
94 SkPMColor4f color = paint.getColor4f();
95 // Only non-null if the paint can be turned into a clear, it can be a local pointer since
96 // the op ctor consumes the value right away if it's provided
97 SkPMColor4f* clearColor = nullptr;
98 if (paint.isTrivial() || paint.isConstantBlendedColor(&color)) {
99 clearColor = &color;
100 }
101
102 return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), clearColor, aaType,
103 edgeAA, stencilSettings, deviceQuad, deviceQuadType, localQuad, localQuadType);
104 }
105
106 // Analysis of the GrPaint to determine the const blend color must be done before, passing
107 // nullptr for constBlendColor disables all scissor-clear optimizations (must keep the
108 // paintColor argument because it is assumed by the GrSimpleMeshDrawOpHelper). Similarly, aaType
109 // is passed to Helper in the initializer list, so incongruities between aaType and edgeFlags
110 // must be resolved prior to calling this constructor.
111 FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, const SkPMColor4f* constBlendColor,
112 GrAAType aaType, GrQuadAAFlags edgeFlags, const GrUserStencilSettings* stencil,
113 const GrPerspQuad& deviceQuad, GrQuadType deviceQuadType,
114 const GrPerspQuad& localQuad, GrQuadType localQuadType)
115 : INHERITED(ClassID())
116 , fHelper(args, aaType, stencil)
117 , fDeviceQuadType(static_cast<unsigned>(deviceQuadType))
118 , fLocalQuadType(static_cast<unsigned>(localQuadType)) {
119 if (constBlendColor) {
120 // The GrPaint is compatible with clearing, and the constant blend color overrides the
121 // paint color (although in most cases they are probably the same)
122 paintColor = *constBlendColor;
123 // However, just because the paint is compatible, the device quad must also be a rect
124 // that is non-AA (AA aligned with pixel bounds should have already been turned into
125 // non-AA).
126 fClearCompatible = deviceQuadType == GrQuadType::kRect && aaType == GrAAType::kNone;
127 } else {
128 // Paint isn't clear compatible
129 fClearCompatible = false;
130 }
131
132 fWideColor = !SkPMColor4fFitsInBytes(paintColor);
133
134 // The color stored with the quad is the clear color if a scissor-clear is decided upon
135 // when executing the op.
136 fQuads.emplace_back(deviceQuad, localQuad, paintColor, edgeFlags);
137 this->setBounds(deviceQuad.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
138 IsZeroArea::kNo);
139 }
140
141 const char* name() const override { return "FillRectOp"; }
142
143 void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
144 return fHelper.visitProxies(func);
145 }
146
147#ifdef SK_DEBUG
148 SkString dumpInfo() const override {
149 SkString str;
150 str.appendf("# draws: %d\n", fQuads.count());
151 str.appendf("Clear compatible: %u\n", static_cast<bool>(fClearCompatible));
152 str.appendf("Device quad type: %u, local quad type: %u\n",
153 fDeviceQuadType, fLocalQuadType);
154 str += fHelper.dumpInfo();
155 for (int i = 0; i < fQuads.count(); i++) {
156 str += fQuads[i].dumpInfo(i);
157
158 }
159 str += INHERITED::dumpInfo();
160 return str;
161 }
162#endif
163
164 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
165 // Initialize aggregate color analysis with the first quad's color (which always exists)
166 SkASSERT(fQuads.count() > 0);
167 GrProcessorAnalysisColor quadColors(fQuads[0].color());
168 // Then combine the colors of any additional quads (e.g. from MakeSet)
169 for (int i = 1; i < fQuads.count(); ++i) {
170 quadColors = GrProcessorAnalysisColor::Combine(quadColors, fQuads[i].color());
Michael Ludwigca91e1f2018-12-10 10:44:44 -0500171 if (quadColors.isUnknown()) {
172 // No point in accumulating additional starting colors, combining cannot make it
173 // less unknown.
174 break;
175 }
Michael Ludwig69858532018-11-28 15:34:34 -0500176 }
Michael Ludwig72ab3462018-12-10 12:43:36 -0500177
178 // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
179 // then the coverage is always 1.0, so specify kNone for more optimal blending.
180 GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
181 GrProcessorAnalysisCoverage::kSingleChannel :
182 GrProcessorAnalysisCoverage::kNone;
183 auto result = fHelper.xpRequiresDstTexture(caps, clip, coverage, &quadColors);
Michael Ludwig69858532018-11-28 15:34:34 -0500184 // If there is a constant color after analysis, that means all of the quads should be set
185 // to the same color (even if they started out with different colors).
186 SkPMColor4f colorOverride;
187 if (quadColors.isConstant(&colorOverride)) {
188 for (int i = 0; i < fQuads.count(); ++i) {
189 fQuads[i].setColor(colorOverride);
190 }
191 }
192
193 return result;
194 }
195
196 FixedFunctionFlags fixedFunctionFlags() const override {
197 // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
198 // the helper's fixed function flags are appropriate.
199 return fHelper.fixedFunctionFlags();
200 }
201
202 DEFINE_OP_CLASS_ID
203
204private:
205 // For GrFillRectOp::MakeSet's use of addQuad
206 // FIXME(reviewer): better to just make addQuad public?
207 friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(GrContext* context, GrPaint&& paint,
208 GrAAType aaType, const SkMatrix& viewMatrix,
209 const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
210 const GrUserStencilSettings* stencilSettings);
211
212 void onPrepareDraws(Target* target) override {
213 TRACE_EVENT0("skia", TRACE_FUNC);
214
215 using Domain = GrQuadPerEdgeAA::Domain;
216 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
217
218 VertexSpec vertexSpec(this->deviceQuadType(),
219 fWideColor ? ColorType::kHalf : ColorType::kByte,
220 this->localQuadType(), fHelper.usesLocalCoords(), Domain::kNo,
Michael Ludwig93aeba02018-12-21 09:50:31 -0500221 fHelper.aaType(), fHelper.compatibleWithAlphaAsCoverage());
Michael Ludwig69858532018-11-28 15:34:34 -0500222
Michael Ludwig467994d2018-12-03 14:58:31 +0000223 sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
Michael Ludwig69858532018-11-28 15:34:34 -0500224 size_t vertexSize = gp->vertexStride();
225
226 const GrBuffer* vbuffer;
227 int vertexOffsetInBuffer = 0;
228
229 // Fill the allocated vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500230 void* vdata = target->makeVertexSpace(
231 vertexSize, fQuads.count() * vertexSpec.verticesPerQuad(),
232 &vbuffer, &vertexOffsetInBuffer);
Michael Ludwig69858532018-11-28 15:34:34 -0500233 if (!vdata) {
234 SkDebugf("Could not allocate vertices\n");
235 return;
236 }
237
238 // vertices pointer advances through vdata based on Tessellate's return value
239 void* vertices = vdata;
240 for (int i = 0; i < fQuads.count(); ++i) {
241 const auto& q = fQuads[i];
242 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, q.deviceQuad(), q.color(),
243 q.localQuad(), kEmptyDomain, q.aaFlags());
244 }
245
246 // Configure the mesh for the vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500247 GrMesh* mesh = target->allocMeshes(1);
248 if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, fQuads.count())) {
249 SkDebugf("Could not allocate indices\n");
250 return;
Michael Ludwig69858532018-11-28 15:34:34 -0500251 }
252 mesh->setVertexData(vbuffer, vertexOffsetInBuffer);
253
254 auto pipe = fHelper.makePipeline(target);
255 target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
256 }
257
258 CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
259 TRACE_EVENT0("skia", TRACE_FUNC);
260 const auto* that = t->cast<FillRectOp>();
261
Michael Ludwig93aeba02018-12-21 09:50:31 -0500262 if ((fHelper.aaType() == GrAAType::kCoverage ||
263 that->fHelper.aaType() == GrAAType::kCoverage) &&
264 fQuads.count() + that->fQuads.count() > GrQuadPerEdgeAA::kNumAAQuadsInIndexBuffer) {
265 // This limit on batch size seems to help on Adreno devices
266 return CombineResult::kCannotCombine;
267 }
268
Michael Ludwig69858532018-11-28 15:34:34 -0500269 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa
270 // draw ops together, so pass true as the last argument.
271 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
272 return CombineResult::kCannotCombine;
273 }
274
275 // If the processor sets are compatible, the two ops are always compatible; it just needs
276 // to adjust the state of the op to be the more general quad and aa types of the two ops.
277
278 // The GrQuadType enum is ordered such that higher values are more general quad types
279 if (that->fDeviceQuadType > fDeviceQuadType) {
280 fDeviceQuadType = that->fDeviceQuadType;
281 }
282 if (that->fLocalQuadType > fLocalQuadType) {
283 fLocalQuadType = that->fLocalQuadType;
284 }
285 fClearCompatible &= that->fClearCompatible;
286 fWideColor |= that->fWideColor;
287
288 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
289 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
290 // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
291 if (fHelper.aaType() == GrAAType::kNone && that->fHelper.aaType() == GrAAType::kCoverage) {
292 fHelper.setAAType(GrAAType::kCoverage);
293 }
294
295 fQuads.push_back_n(that->fQuads.count(), that->fQuads.begin());
296 return CombineResult::kMerged;
297 }
298
299 // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
300 // But since it's avoiding the op list management, it must update the op's bounds. This is only
301 // used with quad sets, which uses the same view matrix for each quad so this assumes that the
302 // device quad type of the new quad is the same as the op's.
303 void addQuad(TransformedQuad&& quad, GrQuadType localQuadType, GrAAType aaType) {
304 SkASSERT(quad.deviceQuad().quadType() <= this->deviceQuadType());
305
306 // The new quad's aa type should be the same as the first quad's or none, except when the
307 // first quad's aa type was already downgraded to none, in which case the stored type must
308 // be lifted to back to the requested type.
309 if (aaType != fHelper.aaType()) {
310 if (aaType != GrAAType::kNone) {
311 // Original quad was downgraded to non-aa, lift back up to this quad's required type
312 SkASSERT(fHelper.aaType() == GrAAType::kNone);
313 fHelper.setAAType(aaType);
314 }
315 // else the new quad could have been downgraded but the other quads can't be, so don't
316 // reset the op's accumulated aa type.
317 }
318
319 // The new quad's local coordinates could differ
320 if (localQuadType > this->localQuadType()) {
321 fLocalQuadType = static_cast<unsigned>(localQuadType);
322 }
323
324 // clear compatible won't need to be updated, since device quad type and paint is the same,
325 // but this quad has a new color, so maybe update wide color
326 fWideColor |= !SkPMColor4fFitsInBytes(quad.color());
327
328 // Update the bounds and add the quad to this op's storage
329 SkRect newBounds = this->bounds();
330 newBounds.joinPossiblyEmptyRect(quad.deviceQuad().bounds());
331 this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
332 IsZeroArea::kNo);
333 fQuads.push_back(std::move(quad));
334 }
335
336 GrQuadType deviceQuadType() const { return static_cast<GrQuadType>(fDeviceQuadType); }
337 GrQuadType localQuadType() const { return static_cast<GrQuadType>(fLocalQuadType); }
338
339 Helper fHelper;
340 SkSTArray<1, TransformedQuad, true> fQuads;
341
342 // While we always store full GrPerspQuads in memory, if the type is known to be simpler we can
343 // optimize our geometry generation.
344 unsigned fDeviceQuadType: 2;
345 unsigned fLocalQuadType: 2;
346 unsigned fWideColor: 1;
347
348 // True if fQuad produced by a rectangle-preserving view matrix, is pixel aligned or non-AA,
349 // and its paint is a constant blended color.
350 unsigned fClearCompatible: 1;
351
352 typedef GrMeshDrawOp INHERITED;
353};
354
355} // anonymous namespace
356
357namespace GrFillRectOp {
358
Michael Ludwig72ab3462018-12-10 12:43:36 -0500359std::unique_ptr<GrDrawOp> MakePerEdge(GrContext* context,
360 GrPaint&& paint,
361 GrAAType aaType,
362 GrQuadAAFlags edgeAA,
363 const SkMatrix& viewMatrix,
364 const SkRect& rect,
365 const GrUserStencilSettings* stencilSettings) {
Michael Ludwig69858532018-11-28 15:34:34 -0500366 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
367 GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
368 GrPerspQuad(rect, SkMatrix::I()), GrQuadType::kRect);
369}
370
Michael Ludwig72ab3462018-12-10 12:43:36 -0500371std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrContext* context,
372 GrPaint&& paint,
373 GrAAType aaType,
374 GrQuadAAFlags edgeAA,
375 const SkMatrix& viewMatrix,
376 const SkMatrix& localMatrix,
377 const SkRect& rect,
378 const GrUserStencilSettings* stencilSettings) {
Michael Ludwig69858532018-11-28 15:34:34 -0500379 GrQuadType localQuadType = GrQuadTypeForTransformedRect(localMatrix);
380 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
381 GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
382 GrPerspQuad(rect, localMatrix), localQuadType);
383}
384
Michael Ludwig72ab3462018-12-10 12:43:36 -0500385std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrContext* context,
386 GrPaint&& paint,
387 GrAAType aaType,
388 GrQuadAAFlags edgeAA,
389 const SkMatrix& viewMatrix,
390 const SkRect& rect,
391 const SkRect& localRect,
392 const GrUserStencilSettings* stencilSettings) {
Michael Ludwig69858532018-11-28 15:34:34 -0500393 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
394 GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
395 GrPerspQuad(localRect, SkMatrix::I()), GrQuadType::kRect);
396}
397
398std::unique_ptr<GrDrawOp> MakeSet(GrContext* context,
399 GrPaint&& paint,
400 GrAAType aaType,
401 const SkMatrix& viewMatrix,
402 const GrRenderTargetContext::QuadSetEntry quads[],
403 int cnt,
404 const GrUserStencilSettings* stencilSettings) {
405 // First make a draw op for the first quad in the set
406 SkASSERT(cnt > 0);
407 GrQuadType deviceQuadType = GrQuadTypeForTransformedRect(viewMatrix);
408
409 paint.setColor4f(quads[0].fColor);
410 std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
411 quads[0].fAAFlags, stencilSettings, GrPerspQuad(quads[0].fRect, viewMatrix),
412 deviceQuadType, GrPerspQuad(quads[0].fRect, quads[0].fLocalMatrix),
413 GrQuadTypeForTransformedRect(quads[0].fLocalMatrix));
414 auto* fillRects = op->cast<FillRectOp>();
415
416 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
417 for (int i = 1; i < cnt; ++i) {
418 GrPerspQuad deviceQuad(quads[i].fRect, viewMatrix);
419
420 GrAAType resolvedAA;
421 GrQuadAAFlags resolvedEdgeFlags;
422 GrResolveAATypeForQuad(aaType, quads[i].fAAFlags, deviceQuad, deviceQuadType,
423 &resolvedAA, &resolvedEdgeFlags);
424
425 fillRects->addQuad({ deviceQuad, GrPerspQuad(quads[i].fRect, quads[i].fLocalMatrix),
426 quads[i].fColor, resolvedEdgeFlags },
427 GrQuadTypeForTransformedRect(quads[i].fLocalMatrix), resolvedAA);
428 }
429
430 return op;
431}
432
Michael Ludwig72ab3462018-12-10 12:43:36 -0500433std::unique_ptr<GrDrawOp> Make(GrContext* context,
434 GrPaint&& paint,
435 GrAAType aaType,
436 const SkMatrix& viewMatrix,
437 const SkRect& rect,
438 const GrUserStencilSettings* stencil) {
439 return MakePerEdge(context, std::move(paint), aaType,
440 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
441 viewMatrix, rect, stencil);
442}
443
444std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
445 GrPaint&& paint,
446 GrAAType aaType,
447 const SkMatrix& viewMatrix,
448 const SkMatrix& localMatrix,
449 const SkRect& rect,
450 const GrUserStencilSettings* stencil) {
451 return MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
452 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
453 viewMatrix, localMatrix, rect, stencil);
454}
455
456std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrContext* context,
457 GrPaint&& paint,
458 GrAAType aaType,
459 const SkMatrix& viewMatrix,
460 const SkRect& rect,
461 const SkRect& localRect,
462 const GrUserStencilSettings* stencil) {
463 return MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
464 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
465 viewMatrix, rect, localRect, stencil);
466}
467
Michael Ludwig69858532018-11-28 15:34:34 -0500468} // namespace GrFillRectOp
469
470#if GR_TEST_UTILS
471
472#include "GrDrawOpTest.h"
473#include "SkGr.h"
474
475GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
476 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
477 SkRect rect = GrTest::TestRect(random);
478
479 GrAAType aaType = GrAAType::kNone;
480 if (random->nextBool()) {
481 aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
482 }
483 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
484 : GrGetRandomStencil(random, context);
485
486 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
487 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
488 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
489 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
490 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
491
492 if (random->nextBool()) {
493 if (random->nextBool()) {
494 if (random->nextBool()) {
495 // Local matrix with a set op
496 uint32_t extraQuadCt = random->nextRangeU(1, 4);
497 SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
498 quads.push_back(
499 {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
500 GrTest::TestMatrixInvertible(random), aaFlags});
501 for (uint32_t i = 0; i < extraQuadCt; ++i) {
502 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
503 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
504 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
505 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
506 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
507
508 quads.push_back(
509 {GrTest::TestRect(random),
510 SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
511 GrTest::TestMatrixInvertible(random), aaFlags});
512 }
513
514 return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
515 quads.begin(), quads.count(), stencil);
516 } else {
517 // Single local matrix
518 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500519 return GrFillRectOp::MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
520 aaFlags, viewMatrix, localMatrix,
521 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500522 }
523 } else {
524 // Pass local rect directly
525 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500526 return GrFillRectOp::MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
527 aaFlags, viewMatrix, rect, localRect,
528 stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500529 }
530 } else {
531 // The simplest constructor
Michael Ludwig72ab3462018-12-10 12:43:36 -0500532 return GrFillRectOp::MakePerEdge(context, std::move(paint), aaType, aaFlags, viewMatrix,
533 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500534 }
535}
536
537#endif