blob: 94f90b310713a68140c4ec6cfa32ddb3d500de64 [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:
Robert Phillipsb97da532019-02-12 15:24:12 -050059 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -050060 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)
Brian Salomon1d835422019-03-13 16:11:44 -040082 , fColorType(GrQuadPerEdgeAA::MinColorType(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
Chris Daltonb8fff0d2019-03-05 10:11:58 -0700124 GrProcessorSet::Analysis finalize(
125 const GrCaps& caps, const GrAppliedClip* clip, GrFSAAType fsaaType) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500126 // Initialize aggregate color analysis with the first quad's color (which always exists)
Michael Ludwigc96fc372019-01-08 15:46:15 -0500127 SkASSERT(this->quadCount() > 0);
128 GrProcessorAnalysisColor quadColors(fDeviceQuads.metadata(0).fColor);
Michael Ludwig69858532018-11-28 15:34:34 -0500129 // Then combine the colors of any additional quads (e.g. from MakeSet)
Michael Ludwigc96fc372019-01-08 15:46:15 -0500130 for (int i = 1; i < this->quadCount(); ++i) {
131 quadColors = GrProcessorAnalysisColor::Combine(quadColors,
132 fDeviceQuads.metadata(i).fColor);
Michael Ludwigca91e1f2018-12-10 10:44:44 -0500133 if (quadColors.isUnknown()) {
134 // No point in accumulating additional starting colors, combining cannot make it
135 // less unknown.
136 break;
137 }
Michael Ludwig69858532018-11-28 15:34:34 -0500138 }
Michael Ludwig72ab3462018-12-10 12:43:36 -0500139
140 // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
141 // then the coverage is always 1.0, so specify kNone for more optimal blending.
142 GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
143 GrProcessorAnalysisCoverage::kSingleChannel :
144 GrProcessorAnalysisCoverage::kNone;
Chris Daltonb8fff0d2019-03-05 10:11:58 -0700145 auto result = fHelper.finalizeProcessors(caps, clip, fsaaType, coverage, &quadColors);
Michael Ludwig69858532018-11-28 15:34:34 -0500146 // If there is a constant color after analysis, that means all of the quads should be set
147 // to the same color (even if they started out with different colors).
148 SkPMColor4f colorOverride;
149 if (quadColors.isConstant(&colorOverride)) {
Michael Ludwigc96fc372019-01-08 15:46:15 -0500150 for (int i = 0; i < this->quadCount(); ++i) {
151 fDeviceQuads.metadata(i).fColor = colorOverride;
Michael Ludwig69858532018-11-28 15:34:34 -0500152 }
153 }
154
155 return result;
156 }
157
158 FixedFunctionFlags fixedFunctionFlags() const override {
159 // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
160 // the helper's fixed function flags are appropriate.
161 return fHelper.fixedFunctionFlags();
162 }
163
164 DEFINE_OP_CLASS_ID
165
166private:
167 // For GrFillRectOp::MakeSet's use of addQuad
Robert Phillipsb97da532019-02-12 15:24:12 -0500168 friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(
169 GrRecordingContext*,
170 GrPaint&&,
171 GrAAType, const SkMatrix& viewMatrix,
Michael Ludwig69858532018-11-28 15:34:34 -0500172 const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
Robert Phillipsb97da532019-02-12 15:24:12 -0500173 const GrUserStencilSettings*);
Michael Ludwig69858532018-11-28 15:34:34 -0500174
Michael Ludwigc96fc372019-01-08 15:46:15 -0500175 void onPrepareDraws(Target* target) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500176 TRACE_EVENT0("skia", TRACE_FUNC);
177
178 using Domain = GrQuadPerEdgeAA::Domain;
179 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
180
Brian Salomon1d835422019-03-13 16:11:44 -0400181 VertexSpec vertexSpec(fDeviceQuads.quadType(), fColorType, fLocalQuads.quadType(),
182 fHelper.usesLocalCoords(), Domain::kNo, fHelper.aaType(),
183 fHelper.compatibleWithAlphaAsCoverage());
Michael Ludwigdcd48212019-01-08 15:28:57 -0500184 // Make sure that if the op thought it was a solid color, the vertex spec does not use
185 // local coords.
186 SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
Michael Ludwig69858532018-11-28 15:34:34 -0500187
Michael Ludwig467994d2018-12-03 14:58:31 +0000188 sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
Michael Ludwig69858532018-11-28 15:34:34 -0500189 size_t vertexSize = gp->vertexStride();
190
Brian Salomon12d22642019-01-29 14:38:50 -0500191 sk_sp<const GrBuffer> vbuffer;
Michael Ludwig69858532018-11-28 15:34:34 -0500192 int vertexOffsetInBuffer = 0;
193
194 // Fill the allocated vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500195 void* vdata = target->makeVertexSpace(
Michael Ludwigc96fc372019-01-08 15:46:15 -0500196 vertexSize, this->quadCount() * vertexSpec.verticesPerQuad(),
Michael Ludwig93aeba02018-12-21 09:50:31 -0500197 &vbuffer, &vertexOffsetInBuffer);
Michael Ludwig69858532018-11-28 15:34:34 -0500198 if (!vdata) {
199 SkDebugf("Could not allocate vertices\n");
200 return;
201 }
202
203 // vertices pointer advances through vdata based on Tessellate's return value
204 void* vertices = vdata;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500205 if (fHelper.isTrivial()) {
206 SkASSERT(fLocalQuads.count() == 0); // No local coords, so send an ignored dummy quad
Michael Ludwige9c57d32019-02-13 13:39:39 -0500207 static const GrPerspQuad kIgnoredLocal(SkRect::MakeEmpty());
208
Michael Ludwigdcd48212019-01-08 15:28:57 -0500209 for (int i = 0; i < this->quadCount(); ++i) {
210 const ColorAndAA& info = fDeviceQuads.metadata(i);
211 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
212 info.fColor, kIgnoredLocal, kEmptyDomain, info.fAAFlags);
213 }
214 } else {
215 SkASSERT(fLocalQuads.count() == fDeviceQuads.count());
216 for (int i = 0; i < this->quadCount(); ++i) {
217 const ColorAndAA& info = fDeviceQuads.metadata(i);
218 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
219 info.fColor, fLocalQuads[i], kEmptyDomain, info.fAAFlags);
220 }
Michael Ludwig69858532018-11-28 15:34:34 -0500221 }
222
223 // Configure the mesh for the vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500224 GrMesh* mesh = target->allocMeshes(1);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500225 if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, this->quadCount())) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500226 SkDebugf("Could not allocate indices\n");
227 return;
Michael Ludwig69858532018-11-28 15:34:34 -0500228 }
Brian Salomon12d22642019-01-29 14:38:50 -0500229 mesh->setVertexData(std::move(vbuffer), vertexOffsetInBuffer);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700230 target->recordDraw(std::move(gp), mesh);
231 }
Michael Ludwig69858532018-11-28 15:34:34 -0500232
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700233 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
234 fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
235 }
Michael Ludwig69858532018-11-28 15:34:34 -0500236
237 CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
238 TRACE_EVENT0("skia", TRACE_FUNC);
239 const auto* that = t->cast<FillRectOp>();
240
Michael Ludwig93aeba02018-12-21 09:50:31 -0500241 if ((fHelper.aaType() == GrAAType::kCoverage ||
242 that->fHelper.aaType() == GrAAType::kCoverage) &&
Michael Ludwigc96fc372019-01-08 15:46:15 -0500243 this->quadCount() + that->quadCount() > GrQuadPerEdgeAA::kNumAAQuadsInIndexBuffer) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500244 // This limit on batch size seems to help on Adreno devices
245 return CombineResult::kCannotCombine;
246 }
247
Michael Ludwigc96fc372019-01-08 15:46:15 -0500248 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
249 // ops together, so pass true as the last argument.
Michael Ludwig69858532018-11-28 15:34:34 -0500250 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
251 return CombineResult::kCannotCombine;
252 }
253
Michael Ludwigdcd48212019-01-08 15:28:57 -0500254 // If the paints were compatible, the trivial/solid-color state should be the same
255 SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
Michael Ludwig69858532018-11-28 15:34:34 -0500256
Michael Ludwigdcd48212019-01-08 15:28:57 -0500257 // If the processor sets are compatible, the two ops are always compatible; it just needs to
258 // adjust the state of the op to be the more general quad and aa types of the two ops and
259 // then concatenate the per-quad data.
Brian Salomon1d835422019-03-13 16:11:44 -0400260 fColorType = SkTMax(fColorType, that->fColorType);
Michael Ludwig69858532018-11-28 15:34:34 -0500261
262 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
263 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
264 // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
265 if (fHelper.aaType() == GrAAType::kNone && that->fHelper.aaType() == GrAAType::kCoverage) {
266 fHelper.setAAType(GrAAType::kCoverage);
267 }
268
Michael Ludwigc96fc372019-01-08 15:46:15 -0500269 fDeviceQuads.concat(that->fDeviceQuads);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500270 if (!fHelper.isTrivial()) {
271 fLocalQuads.concat(that->fLocalQuads);
272 }
Michael Ludwig69858532018-11-28 15:34:34 -0500273 return CombineResult::kMerged;
274 }
275
276 // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
277 // But since it's avoiding the op list management, it must update the op's bounds. This is only
278 // used with quad sets, which uses the same view matrix for each quad so this assumes that the
279 // device quad type of the new quad is the same as the op's.
Michael Ludwigc96fc372019-01-08 15:46:15 -0500280 void addQuad(const GrPerspQuad& deviceQuad, const GrPerspQuad& localQuad,
281 GrQuadType localQuadType, const SkPMColor4f& color, GrQuadAAFlags edgeAA,
282 GrAAType aaType) {
283 SkASSERT(deviceQuad.quadType() <= fDeviceQuads.quadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500284
285 // The new quad's aa type should be the same as the first quad's or none, except when the
286 // first quad's aa type was already downgraded to none, in which case the stored type must
287 // be lifted to back to the requested type.
288 if (aaType != fHelper.aaType()) {
289 if (aaType != GrAAType::kNone) {
290 // Original quad was downgraded to non-aa, lift back up to this quad's required type
291 SkASSERT(fHelper.aaType() == GrAAType::kNone);
292 fHelper.setAAType(aaType);
293 }
294 // else the new quad could have been downgraded but the other quads can't be, so don't
295 // reset the op's accumulated aa type.
296 }
297
Michael Ludwig69858532018-11-28 15:34:34 -0500298 // clear compatible won't need to be updated, since device quad type and paint is the same,
Brian Salomon1d835422019-03-13 16:11:44 -0400299 // but this quad has a new color, so maybe update color type
300 fColorType = SkTMax(fColorType, GrQuadPerEdgeAA::MinColorType(color));
Michael Ludwig69858532018-11-28 15:34:34 -0500301
302 // Update the bounds and add the quad to this op's storage
303 SkRect newBounds = this->bounds();
Michael Ludwigc96fc372019-01-08 15:46:15 -0500304 newBounds.joinPossiblyEmptyRect(deviceQuad.bounds(fDeviceQuads.quadType()));
Michael Ludwig69858532018-11-28 15:34:34 -0500305 this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
306 IsZeroArea::kNo);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500307 fDeviceQuads.push_back(deviceQuad, fDeviceQuads.quadType(), { color, edgeAA });
Michael Ludwigdcd48212019-01-08 15:28:57 -0500308 if (!fHelper.isTrivial()) {
309 fLocalQuads.push_back(localQuad, localQuadType);
310 }
Michael Ludwig69858532018-11-28 15:34:34 -0500311 }
312
Michael Ludwigc96fc372019-01-08 15:46:15 -0500313 int quadCount() const {
314 // Sanity check that the parallel arrays for quad properties all have the same size
Michael Ludwigdcd48212019-01-08 15:28:57 -0500315 SkASSERT(fDeviceQuads.count() == fLocalQuads.count() ||
316 (fLocalQuads.count() == 0 && fHelper.isTrivial()));
Michael Ludwigc96fc372019-01-08 15:46:15 -0500317 return fDeviceQuads.count();
318 }
319
320 struct ColorAndAA {
321 SkPMColor4f fColor;
322 GrQuadAAFlags fAAFlags;
323 };
Michael Ludwig69858532018-11-28 15:34:34 -0500324
325 Helper fHelper;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500326 GrTQuadList<ColorAndAA> fDeviceQuads;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500327 // No metadata attached to the local quads; this list is empty when local coords are not needed.
Michael Ludwigc96fc372019-01-08 15:46:15 -0500328 GrQuadList fLocalQuads;
Michael Ludwig69858532018-11-28 15:34:34 -0500329
Brian Salomon1d835422019-03-13 16:11:44 -0400330 ColorType fColorType;
Michael Ludwig69858532018-11-28 15:34:34 -0500331
Michael Ludwig69858532018-11-28 15:34:34 -0500332 typedef GrMeshDrawOp INHERITED;
333};
334
335} // anonymous namespace
336
337namespace GrFillRectOp {
338
Robert Phillipsb97da532019-02-12 15:24:12 -0500339std::unique_ptr<GrDrawOp> MakePerEdge(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500340 GrPaint&& paint,
341 GrAAType aaType,
342 GrQuadAAFlags edgeAA,
343 const SkMatrix& viewMatrix,
344 const SkRect& rect,
345 const GrUserStencilSettings* stencilSettings) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500346 GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500347 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500348 GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
349 GrPerspQuad(rect), GrQuadType::kRect);
Michael Ludwig69858532018-11-28 15:34:34 -0500350}
351
Robert Phillipsb97da532019-02-12 15:24:12 -0500352std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500353 GrPaint&& paint,
354 GrAAType aaType,
355 GrQuadAAFlags edgeAA,
356 const SkMatrix& viewMatrix,
357 const SkMatrix& localMatrix,
358 const SkRect& rect,
359 const GrUserStencilSettings* stencilSettings) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500360 GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500361 GrQuadType localQuadType = GrQuadTypeForTransformedRect(localMatrix);
362 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500363 GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
364 GrPerspQuad::MakeFromRect(rect, localMatrix), localQuadType);
Michael Ludwig69858532018-11-28 15:34:34 -0500365}
366
Robert Phillipsb97da532019-02-12 15:24:12 -0500367std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500368 GrPaint&& paint,
369 GrAAType aaType,
370 GrQuadAAFlags edgeAA,
371 const SkMatrix& viewMatrix,
372 const SkRect& rect,
373 const SkRect& localRect,
374 const GrUserStencilSettings* stencilSettings) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500375 GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500376 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500377 GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
378 GrPerspQuad(localRect), GrQuadType::kRect);
Michael Ludwig69858532018-11-28 15:34:34 -0500379}
380
Michael Ludwig009b92e2019-02-15 16:03:53 -0500381std::unique_ptr<GrDrawOp> MakePerEdgeQuad(GrRecordingContext* context,
382 GrPaint&& paint,
383 GrAAType aaType,
384 GrQuadAAFlags edgeAA,
385 const SkMatrix& viewMatrix,
386 const SkPoint quad[4],
387 const SkPoint localQuad[4],
388 const GrUserStencilSettings* stencilSettings) {
389 // With arbitrary quads, the quad types are limited to kStandard or kPerspective (unless we
390 // analyzed the points, but callers have more knowledge and should've just use the appropriate
391 // factory, so assume they can't be rectilinear or simpler)
392 GrQuadType deviceType = viewMatrix.hasPerspective() ? GrQuadType::kPerspective
393 : GrQuadType::kStandard;
394 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
395 GrPerspQuad::MakeFromSkQuad(quad, viewMatrix), deviceType,
396 GrPerspQuad::MakeFromSkQuad(localQuad ? localQuad : quad,
397 SkMatrix::I()), GrQuadType::kStandard);
398}
399
Robert Phillipsb97da532019-02-12 15:24:12 -0500400std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -0500401 GrPaint&& paint,
402 GrAAType aaType,
403 const SkMatrix& viewMatrix,
404 const GrRenderTargetContext::QuadSetEntry quads[],
405 int cnt,
406 const GrUserStencilSettings* stencilSettings) {
407 // First make a draw op for the first quad in the set
408 SkASSERT(cnt > 0);
409 GrQuadType deviceQuadType = GrQuadTypeForTransformedRect(viewMatrix);
410
411 paint.setColor4f(quads[0].fColor);
412 std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500413 quads[0].fAAFlags, stencilSettings,
414 GrPerspQuad::MakeFromRect(quads[0].fRect, viewMatrix), deviceQuadType,
415 GrPerspQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix),
Michael Ludwig69858532018-11-28 15:34:34 -0500416 GrQuadTypeForTransformedRect(quads[0].fLocalMatrix));
417 auto* fillRects = op->cast<FillRectOp>();
418
419 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
420 for (int i = 1; i < cnt; ++i) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500421 GrPerspQuad deviceQuad = GrPerspQuad::MakeFromRect(quads[i].fRect, viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500422
423 GrAAType resolvedAA;
424 GrQuadAAFlags resolvedEdgeFlags;
425 GrResolveAATypeForQuad(aaType, quads[i].fAAFlags, deviceQuad, deviceQuadType,
426 &resolvedAA, &resolvedEdgeFlags);
427
Michael Ludwige9c57d32019-02-13 13:39:39 -0500428 fillRects->addQuad(deviceQuad,
429 GrPerspQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
Michael Ludwigc96fc372019-01-08 15:46:15 -0500430 GrQuadTypeForTransformedRect(quads[i].fLocalMatrix), quads[i].fColor,
431 resolvedEdgeFlags,resolvedAA);
Michael Ludwig69858532018-11-28 15:34:34 -0500432 }
433
434 return op;
435}
436
Robert Phillipsb97da532019-02-12 15:24:12 -0500437std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500438 GrPaint&& paint,
439 GrAAType aaType,
440 const SkMatrix& viewMatrix,
441 const SkRect& rect,
442 const GrUserStencilSettings* stencil) {
443 return MakePerEdge(context, std::move(paint), aaType,
444 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
445 viewMatrix, rect, stencil);
446}
447
Robert Phillipsb97da532019-02-12 15:24:12 -0500448std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500449 GrPaint&& paint,
450 GrAAType aaType,
451 const SkMatrix& viewMatrix,
452 const SkMatrix& localMatrix,
453 const SkRect& rect,
454 const GrUserStencilSettings* stencil) {
455 return MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
456 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
457 viewMatrix, localMatrix, rect, stencil);
458}
459
Robert Phillipsb97da532019-02-12 15:24:12 -0500460std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500461 GrPaint&& paint,
462 GrAAType aaType,
463 const SkMatrix& viewMatrix,
464 const SkRect& rect,
465 const SkRect& localRect,
466 const GrUserStencilSettings* stencil) {
467 return MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
468 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
469 viewMatrix, rect, localRect, stencil);
470}
471
Michael Ludwig69858532018-11-28 15:34:34 -0500472} // namespace GrFillRectOp
473
474#if GR_TEST_UTILS
475
476#include "GrDrawOpTest.h"
477#include "SkGr.h"
478
479GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
480 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
481 SkRect rect = GrTest::TestRect(random);
482
483 GrAAType aaType = GrAAType::kNone;
484 if (random->nextBool()) {
485 aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
486 }
487 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
488 : GrGetRandomStencil(random, context);
489
490 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
491 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
492 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
493 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
494 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
495
496 if (random->nextBool()) {
497 if (random->nextBool()) {
498 if (random->nextBool()) {
499 // Local matrix with a set op
500 uint32_t extraQuadCt = random->nextRangeU(1, 4);
501 SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
502 quads.push_back(
503 {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
504 GrTest::TestMatrixInvertible(random), aaFlags});
505 for (uint32_t i = 0; i < extraQuadCt; ++i) {
506 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
507 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
508 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
509 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
510 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
511
512 quads.push_back(
513 {GrTest::TestRect(random),
514 SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
515 GrTest::TestMatrixInvertible(random), aaFlags});
516 }
517
518 return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
519 quads.begin(), quads.count(), stencil);
520 } else {
521 // Single local matrix
522 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500523 return GrFillRectOp::MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
524 aaFlags, viewMatrix, localMatrix,
525 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500526 }
527 } else {
528 // Pass local rect directly
529 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500530 return GrFillRectOp::MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
531 aaFlags, viewMatrix, rect, localRect,
532 stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500533 }
534 } else {
535 // The simplest constructor
Michael Ludwig72ab3462018-12-10 12:43:36 -0500536 return GrFillRectOp::MakePerEdge(context, std::move(paint), aaType, aaFlags, viewMatrix,
537 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500538 }
539}
540
541#endif