blob: 0ff0322ab924f6d5c3d73990046244b80908599b [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
Michael Ludwigc96fc372019-01-08 15:46:15 -050027#ifdef SK_DEBUG
28static SkString dump_quad_info(int index, const GrPerspQuad& deviceQuad,
29 const GrPerspQuad& localQuad, const SkPMColor4f& color,
30 GrQuadAAFlags aaFlags) {
31 SkString str;
32 str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
33 " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
34 "(%.2f, %.2f, %.2f)],\n"
35 " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
36 "(%.2f, %.2f, %.2f)]\n",
37 index, color.fR, color.fG, color.fB, color.fA,
38 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
39 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
40 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
41 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
42 deviceQuad.x(0), deviceQuad.y(0), deviceQuad.w(0),
43 deviceQuad.x(1), deviceQuad.y(1), deviceQuad.w(1),
44 deviceQuad.x(2), deviceQuad.y(2), deviceQuad.w(2),
45 deviceQuad.x(3), deviceQuad.y(3), deviceQuad.w(3),
46 localQuad.x(0), localQuad.y(0), localQuad.w(0),
47 localQuad.x(1), localQuad.y(1), localQuad.w(1),
48 localQuad.x(2), localQuad.y(2), localQuad.w(2),
49 localQuad.x(3), localQuad.y(3), localQuad.w(3));
50 return str;
51}
52#endif
Michael Ludwig69858532018-11-28 15:34:34 -050053
Michael Ludwig69858532018-11-28 15:34:34 -050054class FillRectOp final : public GrMeshDrawOp {
55private:
56 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
57
58public:
59 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
60 GrPaint&& paint,
61 GrAAType aaType,
62 GrQuadAAFlags edgeAA,
63 const GrUserStencilSettings* stencilSettings,
64 const GrPerspQuad& deviceQuad,
65 GrQuadType deviceQuadType,
66 const GrPerspQuad& localQuad,
67 GrQuadType localQuadType) {
68 // Clean up deviations between aaType and edgeAA
69 GrResolveAATypeForQuad(aaType, edgeAA, deviceQuad, deviceQuadType, &aaType, &edgeAA);
Michael Ludwigdcd48212019-01-08 15:28:57 -050070 return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
71 stencilSettings, deviceQuad, deviceQuadType, localQuad, localQuadType);
Michael Ludwig69858532018-11-28 15:34:34 -050072 }
73
Michael Ludwigdcd48212019-01-08 15:28:57 -050074 // aaType is passed to Helper in the initializer list, so incongruities between aaType and
75 // edgeFlags must be resolved prior to calling this constructor.
76 FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
77 GrQuadAAFlags edgeFlags, const GrUserStencilSettings* stencil,
Michael Ludwig69858532018-11-28 15:34:34 -050078 const GrPerspQuad& deviceQuad, GrQuadType deviceQuadType,
79 const GrPerspQuad& localQuad, GrQuadType localQuadType)
80 : INHERITED(ClassID())
Michael Ludwigdcd48212019-01-08 15:28:57 -050081 , fHelper(args, aaType, stencil)
82 , fWideColor(!SkPMColor4fFitsInBytes(paintColor)) {
Michael Ludwig69858532018-11-28 15:34:34 -050083 // The color stored with the quad is the clear color if a scissor-clear is decided upon
84 // when executing the op.
Michael Ludwigc96fc372019-01-08 15:46:15 -050085 fDeviceQuads.push_back(deviceQuad, deviceQuadType, { paintColor, edgeFlags });
Michael Ludwigdcd48212019-01-08 15:28:57 -050086
87 if (!fHelper.isTrivial()) {
88 // Conservatively keep track of the local coordinates; it may be that the paint doesn't
89 // need them after analysis is finished. If the paint is known to be solid up front they
90 // can be skipped entirely.
91 fLocalQuads.push_back(localQuad, localQuadType);
92 }
Michael Ludwigc96fc372019-01-08 15:46:15 -050093 this->setBounds(deviceQuad.bounds(deviceQuadType),
94 HasAABloat(aaType == GrAAType::kCoverage), IsZeroArea::kNo);
Michael Ludwig69858532018-11-28 15:34:34 -050095 }
96
97 const char* name() const override { return "FillRectOp"; }
98
99 void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
100 return fHelper.visitProxies(func);
101 }
102
103#ifdef SK_DEBUG
104 SkString dumpInfo() const override {
105 SkString str;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500106 str.appendf("# draws: %u\n", this->quadCount());
Michael Ludwig69858532018-11-28 15:34:34 -0500107 str.appendf("Device quad type: %u, local quad type: %u\n",
Michael Ludwigc96fc372019-01-08 15:46:15 -0500108 (uint32_t) fDeviceQuads.quadType(), (uint32_t) fLocalQuads.quadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500109 str += fHelper.dumpInfo();
Michael Ludwigc96fc372019-01-08 15:46:15 -0500110 GrPerspQuad device, local;
111 for (int i = 0; i < this->quadCount(); i++) {
112 device = fDeviceQuads[i];
113 const ColorAndAA& info = fDeviceQuads.metadata(i);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500114 if (!fHelper.isTrivial()) {
115 local = fLocalQuads[i];
116 }
Michael Ludwigc96fc372019-01-08 15:46:15 -0500117 str += dump_quad_info(i, device, local, info.fColor, info.fAAFlags);
Michael Ludwig69858532018-11-28 15:34:34 -0500118 }
119 str += INHERITED::dumpInfo();
120 return str;
121 }
122#endif
123
124 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
125 // Initialize aggregate color analysis with the first quad's color (which always exists)
Michael Ludwigc96fc372019-01-08 15:46:15 -0500126 SkASSERT(this->quadCount() > 0);
127 GrProcessorAnalysisColor quadColors(fDeviceQuads.metadata(0).fColor);
Michael Ludwig69858532018-11-28 15:34:34 -0500128 // Then combine the colors of any additional quads (e.g. from MakeSet)
Michael Ludwigc96fc372019-01-08 15:46:15 -0500129 for (int i = 1; i < this->quadCount(); ++i) {
130 quadColors = GrProcessorAnalysisColor::Combine(quadColors,
131 fDeviceQuads.metadata(i).fColor);
Michael Ludwigca91e1f2018-12-10 10:44:44 -0500132 if (quadColors.isUnknown()) {
133 // No point in accumulating additional starting colors, combining cannot make it
134 // less unknown.
135 break;
136 }
Michael Ludwig69858532018-11-28 15:34:34 -0500137 }
Michael Ludwig72ab3462018-12-10 12:43:36 -0500138
139 // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
140 // then the coverage is always 1.0, so specify kNone for more optimal blending.
141 GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
142 GrProcessorAnalysisCoverage::kSingleChannel :
143 GrProcessorAnalysisCoverage::kNone;
144 auto result = fHelper.xpRequiresDstTexture(caps, clip, coverage, &quadColors);
Michael Ludwig69858532018-11-28 15:34:34 -0500145 // If there is a constant color after analysis, that means all of the quads should be set
146 // to the same color (even if they started out with different colors).
147 SkPMColor4f colorOverride;
148 if (quadColors.isConstant(&colorOverride)) {
Michael Ludwigc96fc372019-01-08 15:46:15 -0500149 for (int i = 0; i < this->quadCount(); ++i) {
150 fDeviceQuads.metadata(i).fColor = colorOverride;
Michael Ludwig69858532018-11-28 15:34:34 -0500151 }
152 }
153
154 return result;
155 }
156
157 FixedFunctionFlags fixedFunctionFlags() const override {
158 // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
159 // the helper's fixed function flags are appropriate.
160 return fHelper.fixedFunctionFlags();
161 }
162
163 DEFINE_OP_CLASS_ID
164
165private:
166 // For GrFillRectOp::MakeSet's use of addQuad
Michael Ludwig69858532018-11-28 15:34:34 -0500167 friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(GrContext* context, GrPaint&& paint,
168 GrAAType aaType, const SkMatrix& viewMatrix,
169 const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
170 const GrUserStencilSettings* stencilSettings);
171
Michael Ludwigc96fc372019-01-08 15:46:15 -0500172 void onPrepareDraws(Target* target) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500173 TRACE_EVENT0("skia", TRACE_FUNC);
174
175 using Domain = GrQuadPerEdgeAA::Domain;
176 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
177
Michael Ludwigc96fc372019-01-08 15:46:15 -0500178 VertexSpec vertexSpec(fDeviceQuads.quadType(),
Michael Ludwig69858532018-11-28 15:34:34 -0500179 fWideColor ? ColorType::kHalf : ColorType::kByte,
Michael Ludwigc96fc372019-01-08 15:46:15 -0500180 fLocalQuads.quadType(), fHelper.usesLocalCoords(), Domain::kNo,
Michael Ludwig93aeba02018-12-21 09:50:31 -0500181 fHelper.aaType(), fHelper.compatibleWithAlphaAsCoverage());
Michael Ludwigdcd48212019-01-08 15:28:57 -0500182 // Make sure that if the op thought it was a solid color, the vertex spec does not use
183 // local coords.
184 SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
Michael Ludwig69858532018-11-28 15:34:34 -0500185
Michael Ludwig467994d2018-12-03 14:58:31 +0000186 sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
Michael Ludwig69858532018-11-28 15:34:34 -0500187 size_t vertexSize = gp->vertexStride();
188
189 const GrBuffer* vbuffer;
190 int vertexOffsetInBuffer = 0;
191
192 // Fill the allocated vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500193 void* vdata = target->makeVertexSpace(
Michael Ludwigc96fc372019-01-08 15:46:15 -0500194 vertexSize, this->quadCount() * vertexSpec.verticesPerQuad(),
Michael Ludwig93aeba02018-12-21 09:50:31 -0500195 &vbuffer, &vertexOffsetInBuffer);
Michael Ludwig69858532018-11-28 15:34:34 -0500196 if (!vdata) {
197 SkDebugf("Could not allocate vertices\n");
198 return;
199 }
200
201 // vertices pointer advances through vdata based on Tessellate's return value
202 void* vertices = vdata;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500203 if (fHelper.isTrivial()) {
204 SkASSERT(fLocalQuads.count() == 0); // No local coords, so send an ignored dummy quad
205 static const GrPerspQuad kIgnoredLocal(SkRect::MakeEmpty(), SkMatrix::I());
206 for (int i = 0; i < this->quadCount(); ++i) {
207 const ColorAndAA& info = fDeviceQuads.metadata(i);
208 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
209 info.fColor, kIgnoredLocal, kEmptyDomain, info.fAAFlags);
210 }
211 } else {
212 SkASSERT(fLocalQuads.count() == fDeviceQuads.count());
213 for (int i = 0; i < this->quadCount(); ++i) {
214 const ColorAndAA& info = fDeviceQuads.metadata(i);
215 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
216 info.fColor, fLocalQuads[i], kEmptyDomain, info.fAAFlags);
217 }
Michael Ludwig69858532018-11-28 15:34:34 -0500218 }
219
220 // Configure the mesh for the vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500221 GrMesh* mesh = target->allocMeshes(1);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500222 if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, this->quadCount())) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500223 SkDebugf("Could not allocate indices\n");
224 return;
Michael Ludwig69858532018-11-28 15:34:34 -0500225 }
226 mesh->setVertexData(vbuffer, vertexOffsetInBuffer);
227
228 auto pipe = fHelper.makePipeline(target);
229 target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
230 }
231
232 CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
233 TRACE_EVENT0("skia", TRACE_FUNC);
234 const auto* that = t->cast<FillRectOp>();
235
Michael Ludwig93aeba02018-12-21 09:50:31 -0500236 if ((fHelper.aaType() == GrAAType::kCoverage ||
237 that->fHelper.aaType() == GrAAType::kCoverage) &&
Michael Ludwigc96fc372019-01-08 15:46:15 -0500238 this->quadCount() + that->quadCount() > GrQuadPerEdgeAA::kNumAAQuadsInIndexBuffer) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500239 // This limit on batch size seems to help on Adreno devices
240 return CombineResult::kCannotCombine;
241 }
242
Michael Ludwigc96fc372019-01-08 15:46:15 -0500243 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
244 // ops together, so pass true as the last argument.
Michael Ludwig69858532018-11-28 15:34:34 -0500245 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
246 return CombineResult::kCannotCombine;
247 }
248
Michael Ludwigdcd48212019-01-08 15:28:57 -0500249 // If the paints were compatible, the trivial/solid-color state should be the same
250 SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
Michael Ludwig69858532018-11-28 15:34:34 -0500251
Michael Ludwigdcd48212019-01-08 15:28:57 -0500252 // If the processor sets are compatible, the two ops are always compatible; it just needs to
253 // adjust the state of the op to be the more general quad and aa types of the two ops and
254 // then concatenate the per-quad data.
Michael Ludwig69858532018-11-28 15:34:34 -0500255 fWideColor |= that->fWideColor;
256
257 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
258 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
259 // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
260 if (fHelper.aaType() == GrAAType::kNone && that->fHelper.aaType() == GrAAType::kCoverage) {
261 fHelper.setAAType(GrAAType::kCoverage);
262 }
263
Michael Ludwigc96fc372019-01-08 15:46:15 -0500264 fDeviceQuads.concat(that->fDeviceQuads);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500265 if (!fHelper.isTrivial()) {
266 fLocalQuads.concat(that->fLocalQuads);
267 }
Michael Ludwig69858532018-11-28 15:34:34 -0500268 return CombineResult::kMerged;
269 }
270
271 // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
272 // But since it's avoiding the op list management, it must update the op's bounds. This is only
273 // used with quad sets, which uses the same view matrix for each quad so this assumes that the
274 // device quad type of the new quad is the same as the op's.
Michael Ludwigc96fc372019-01-08 15:46:15 -0500275 void addQuad(const GrPerspQuad& deviceQuad, const GrPerspQuad& localQuad,
276 GrQuadType localQuadType, const SkPMColor4f& color, GrQuadAAFlags edgeAA,
277 GrAAType aaType) {
278 SkASSERT(deviceQuad.quadType() <= fDeviceQuads.quadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500279
280 // The new quad's aa type should be the same as the first quad's or none, except when the
281 // first quad's aa type was already downgraded to none, in which case the stored type must
282 // be lifted to back to the requested type.
283 if (aaType != fHelper.aaType()) {
284 if (aaType != GrAAType::kNone) {
285 // Original quad was downgraded to non-aa, lift back up to this quad's required type
286 SkASSERT(fHelper.aaType() == GrAAType::kNone);
287 fHelper.setAAType(aaType);
288 }
289 // else the new quad could have been downgraded but the other quads can't be, so don't
290 // reset the op's accumulated aa type.
291 }
292
Michael Ludwig69858532018-11-28 15:34:34 -0500293 // clear compatible won't need to be updated, since device quad type and paint is the same,
294 // but this quad has a new color, so maybe update wide color
Michael Ludwigc96fc372019-01-08 15:46:15 -0500295 fWideColor |= !SkPMColor4fFitsInBytes(color);
Michael Ludwig69858532018-11-28 15:34:34 -0500296
297 // Update the bounds and add the quad to this op's storage
298 SkRect newBounds = this->bounds();
Michael Ludwigc96fc372019-01-08 15:46:15 -0500299 newBounds.joinPossiblyEmptyRect(deviceQuad.bounds(fDeviceQuads.quadType()));
Michael Ludwig69858532018-11-28 15:34:34 -0500300 this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
301 IsZeroArea::kNo);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500302 fDeviceQuads.push_back(deviceQuad, fDeviceQuads.quadType(), { color, edgeAA });
Michael Ludwigdcd48212019-01-08 15:28:57 -0500303 if (!fHelper.isTrivial()) {
304 fLocalQuads.push_back(localQuad, localQuadType);
305 }
Michael Ludwig69858532018-11-28 15:34:34 -0500306 }
307
Michael Ludwigc96fc372019-01-08 15:46:15 -0500308 int quadCount() const {
309 // Sanity check that the parallel arrays for quad properties all have the same size
Michael Ludwigdcd48212019-01-08 15:28:57 -0500310 SkASSERT(fDeviceQuads.count() == fLocalQuads.count() ||
311 (fLocalQuads.count() == 0 && fHelper.isTrivial()));
Michael Ludwigc96fc372019-01-08 15:46:15 -0500312 return fDeviceQuads.count();
313 }
314
315 struct ColorAndAA {
316 SkPMColor4f fColor;
317 GrQuadAAFlags fAAFlags;
318 };
Michael Ludwig69858532018-11-28 15:34:34 -0500319
320 Helper fHelper;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500321 GrTQuadList<ColorAndAA> fDeviceQuads;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500322 // No metadata attached to the local quads; this list is empty when local coords are not needed.
Michael Ludwigc96fc372019-01-08 15:46:15 -0500323 GrQuadList fLocalQuads;
Michael Ludwig69858532018-11-28 15:34:34 -0500324
Michael Ludwig69858532018-11-28 15:34:34 -0500325 unsigned fWideColor: 1;
326
Michael Ludwig69858532018-11-28 15:34:34 -0500327 typedef GrMeshDrawOp INHERITED;
328};
329
330} // anonymous namespace
331
332namespace GrFillRectOp {
333
Michael Ludwig72ab3462018-12-10 12:43:36 -0500334std::unique_ptr<GrDrawOp> MakePerEdge(GrContext* context,
335 GrPaint&& paint,
336 GrAAType aaType,
337 GrQuadAAFlags edgeAA,
338 const SkMatrix& viewMatrix,
339 const SkRect& rect,
340 const GrUserStencilSettings* stencilSettings) {
Michael Ludwig69858532018-11-28 15:34:34 -0500341 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
342 GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
343 GrPerspQuad(rect, SkMatrix::I()), GrQuadType::kRect);
344}
345
Michael Ludwig72ab3462018-12-10 12:43:36 -0500346std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrContext* context,
347 GrPaint&& paint,
348 GrAAType aaType,
349 GrQuadAAFlags edgeAA,
350 const SkMatrix& viewMatrix,
351 const SkMatrix& localMatrix,
352 const SkRect& rect,
353 const GrUserStencilSettings* stencilSettings) {
Michael Ludwig69858532018-11-28 15:34:34 -0500354 GrQuadType localQuadType = GrQuadTypeForTransformedRect(localMatrix);
355 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
356 GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
357 GrPerspQuad(rect, localMatrix), localQuadType);
358}
359
Michael Ludwig72ab3462018-12-10 12:43:36 -0500360std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrContext* context,
361 GrPaint&& paint,
362 GrAAType aaType,
363 GrQuadAAFlags edgeAA,
364 const SkMatrix& viewMatrix,
365 const SkRect& rect,
366 const SkRect& localRect,
367 const GrUserStencilSettings* stencilSettings) {
Michael Ludwig69858532018-11-28 15:34:34 -0500368 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
369 GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
370 GrPerspQuad(localRect, SkMatrix::I()), GrQuadType::kRect);
371}
372
373std::unique_ptr<GrDrawOp> MakeSet(GrContext* context,
374 GrPaint&& paint,
375 GrAAType aaType,
376 const SkMatrix& viewMatrix,
377 const GrRenderTargetContext::QuadSetEntry quads[],
378 int cnt,
379 const GrUserStencilSettings* stencilSettings) {
380 // First make a draw op for the first quad in the set
381 SkASSERT(cnt > 0);
382 GrQuadType deviceQuadType = GrQuadTypeForTransformedRect(viewMatrix);
383
384 paint.setColor4f(quads[0].fColor);
385 std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
386 quads[0].fAAFlags, stencilSettings, GrPerspQuad(quads[0].fRect, viewMatrix),
387 deviceQuadType, GrPerspQuad(quads[0].fRect, quads[0].fLocalMatrix),
388 GrQuadTypeForTransformedRect(quads[0].fLocalMatrix));
389 auto* fillRects = op->cast<FillRectOp>();
390
391 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
392 for (int i = 1; i < cnt; ++i) {
393 GrPerspQuad deviceQuad(quads[i].fRect, viewMatrix);
394
395 GrAAType resolvedAA;
396 GrQuadAAFlags resolvedEdgeFlags;
397 GrResolveAATypeForQuad(aaType, quads[i].fAAFlags, deviceQuad, deviceQuadType,
398 &resolvedAA, &resolvedEdgeFlags);
399
Michael Ludwigc96fc372019-01-08 15:46:15 -0500400 fillRects->addQuad(deviceQuad, GrPerspQuad(quads[i].fRect, quads[i].fLocalMatrix),
401 GrQuadTypeForTransformedRect(quads[i].fLocalMatrix), quads[i].fColor,
402 resolvedEdgeFlags,resolvedAA);
Michael Ludwig69858532018-11-28 15:34:34 -0500403 }
404
405 return op;
406}
407
Michael Ludwig72ab3462018-12-10 12:43:36 -0500408std::unique_ptr<GrDrawOp> Make(GrContext* context,
409 GrPaint&& paint,
410 GrAAType aaType,
411 const SkMatrix& viewMatrix,
412 const SkRect& rect,
413 const GrUserStencilSettings* stencil) {
414 return MakePerEdge(context, std::move(paint), aaType,
415 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
416 viewMatrix, rect, stencil);
417}
418
419std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
420 GrPaint&& paint,
421 GrAAType aaType,
422 const SkMatrix& viewMatrix,
423 const SkMatrix& localMatrix,
424 const SkRect& rect,
425 const GrUserStencilSettings* stencil) {
426 return MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
427 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
428 viewMatrix, localMatrix, rect, stencil);
429}
430
431std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrContext* context,
432 GrPaint&& paint,
433 GrAAType aaType,
434 const SkMatrix& viewMatrix,
435 const SkRect& rect,
436 const SkRect& localRect,
437 const GrUserStencilSettings* stencil) {
438 return MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
439 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
440 viewMatrix, rect, localRect, stencil);
441}
442
Michael Ludwig69858532018-11-28 15:34:34 -0500443} // namespace GrFillRectOp
444
445#if GR_TEST_UTILS
446
447#include "GrDrawOpTest.h"
448#include "SkGr.h"
449
450GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
451 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
452 SkRect rect = GrTest::TestRect(random);
453
454 GrAAType aaType = GrAAType::kNone;
455 if (random->nextBool()) {
456 aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
457 }
458 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
459 : GrGetRandomStencil(random, context);
460
461 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
462 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
463 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
464 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
465 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
466
467 if (random->nextBool()) {
468 if (random->nextBool()) {
469 if (random->nextBool()) {
470 // Local matrix with a set op
471 uint32_t extraQuadCt = random->nextRangeU(1, 4);
472 SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
473 quads.push_back(
474 {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
475 GrTest::TestMatrixInvertible(random), aaFlags});
476 for (uint32_t i = 0; i < extraQuadCt; ++i) {
477 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
478 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
479 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
480 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
481 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
482
483 quads.push_back(
484 {GrTest::TestRect(random),
485 SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
486 GrTest::TestMatrixInvertible(random), aaFlags});
487 }
488
489 return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
490 quads.begin(), quads.count(), stencil);
491 } else {
492 // Single local matrix
493 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500494 return GrFillRectOp::MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
495 aaFlags, viewMatrix, localMatrix,
496 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500497 }
498 } else {
499 // Pass local rect directly
500 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500501 return GrFillRectOp::MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
502 aaFlags, viewMatrix, rect, localRect,
503 stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500504 }
505 } else {
506 // The simplest constructor
Michael Ludwig72ab3462018-12-10 12:43:36 -0500507 return GrFillRectOp::MakePerEdge(context, std::move(paint), aaType, aaFlags, viewMatrix,
508 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500509 }
510}
511
512#endif