blob: f6f73d52d0fad5659323f189f2bf9daaaba1f386 [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
Brian Salomonf4191392019-03-14 15:46:20 -040010#include "GrCaps.h"
Michael Ludwig69858532018-11-28 15:34:34 -050011#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
23namespace {
24
25using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
26using ColorType = GrQuadPerEdgeAA::ColorType;
27
Michael Ludwigc96fc372019-01-08 15:46:15 -050028#ifdef SK_DEBUG
29static 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
Michael Ludwig69858532018-11-28 15:34:34 -050054
Michael Ludwig69858532018-11-28 15:34:34 -050055class FillRectOp final : public GrMeshDrawOp {
56private:
57 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
58
59public:
Robert Phillipsb97da532019-02-12 15:24:12 -050060 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -050061 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);
Michael Ludwigdcd48212019-01-08 15:28:57 -050071 return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
72 stencilSettings, deviceQuad, deviceQuadType, localQuad, localQuadType);
Michael Ludwig69858532018-11-28 15:34:34 -050073 }
74
Michael Ludwigdcd48212019-01-08 15:28:57 -050075 // aaType is passed to Helper in the initializer list, so incongruities between aaType and
76 // edgeFlags must be resolved prior to calling this constructor.
77 FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
78 GrQuadAAFlags edgeFlags, const GrUserStencilSettings* stencil,
Michael Ludwig69858532018-11-28 15:34:34 -050079 const GrPerspQuad& deviceQuad, GrQuadType deviceQuadType,
80 const GrPerspQuad& localQuad, GrQuadType localQuadType)
81 : INHERITED(ClassID())
Michael Ludwigdcd48212019-01-08 15:28:57 -050082 , fHelper(args, aaType, stencil)
Brian Salomon1d835422019-03-13 16:11:44 -040083 , fColorType(GrQuadPerEdgeAA::MinColorType(paintColor)) {
Michael Ludwig69858532018-11-28 15:34:34 -050084 // The color stored with the quad is the clear color if a scissor-clear is decided upon
85 // when executing the op.
Michael Ludwigc96fc372019-01-08 15:46:15 -050086 fDeviceQuads.push_back(deviceQuad, deviceQuadType, { paintColor, edgeFlags });
Michael Ludwigdcd48212019-01-08 15:28:57 -050087
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 }
Michael Ludwigc96fc372019-01-08 15:46:15 -050094 this->setBounds(deviceQuad.bounds(deviceQuadType),
95 HasAABloat(aaType == GrAAType::kCoverage), IsZeroArea::kNo);
Michael Ludwig69858532018-11-28 15:34:34 -050096 }
97
98 const char* name() const override { return "FillRectOp"; }
99
100 void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
101 return fHelper.visitProxies(func);
102 }
103
104#ifdef SK_DEBUG
105 SkString dumpInfo() const override {
106 SkString str;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500107 str.appendf("# draws: %u\n", this->quadCount());
Michael Ludwig69858532018-11-28 15:34:34 -0500108 str.appendf("Device quad type: %u, local quad type: %u\n",
Michael Ludwigc96fc372019-01-08 15:46:15 -0500109 (uint32_t) fDeviceQuads.quadType(), (uint32_t) fLocalQuads.quadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500110 str += fHelper.dumpInfo();
Michael Ludwigc96fc372019-01-08 15:46:15 -0500111 GrPerspQuad device, local;
112 for (int i = 0; i < this->quadCount(); i++) {
113 device = fDeviceQuads[i];
114 const ColorAndAA& info = fDeviceQuads.metadata(i);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500115 if (!fHelper.isTrivial()) {
116 local = fLocalQuads[i];
117 }
Michael Ludwigc96fc372019-01-08 15:46:15 -0500118 str += dump_quad_info(i, device, local, info.fColor, info.fAAFlags);
Michael Ludwig69858532018-11-28 15:34:34 -0500119 }
120 str += INHERITED::dumpInfo();
121 return str;
122 }
123#endif
124
Brian Osman5ced0bf2019-03-15 10:15:29 -0400125 GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
126 GrFSAAType fsaaType, GrClampType clampType) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500127 // Initialize aggregate color analysis with the first quad's color (which always exists)
Michael Ludwigc96fc372019-01-08 15:46:15 -0500128 SkASSERT(this->quadCount() > 0);
129 GrProcessorAnalysisColor quadColors(fDeviceQuads.metadata(0).fColor);
Michael Ludwig69858532018-11-28 15:34:34 -0500130 // Then combine the colors of any additional quads (e.g. from MakeSet)
Michael Ludwigc96fc372019-01-08 15:46:15 -0500131 for (int i = 1; i < this->quadCount(); ++i) {
132 quadColors = GrProcessorAnalysisColor::Combine(quadColors,
133 fDeviceQuads.metadata(i).fColor);
Michael Ludwigca91e1f2018-12-10 10:44:44 -0500134 if (quadColors.isUnknown()) {
135 // No point in accumulating additional starting colors, combining cannot make it
136 // less unknown.
137 break;
138 }
Michael Ludwig69858532018-11-28 15:34:34 -0500139 }
Michael Ludwig72ab3462018-12-10 12:43:36 -0500140
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;
Brian Osman5ced0bf2019-03-15 10:15:29 -0400146 auto result = fHelper.finalizeProcessors(
147 caps, clip, fsaaType, clampType, coverage, &quadColors);
Michael Ludwig69858532018-11-28 15:34:34 -0500148 // 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)) {
Brian Salomonf4191392019-03-14 15:46:20 -0400152 // 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 }
Michael Ludwigc96fc372019-01-08 15:46:15 -0500162 for (int i = 0; i < this->quadCount(); ++i) {
163 fDeviceQuads.metadata(i).fColor = colorOverride;
Michael Ludwig69858532018-11-28 15:34:34 -0500164 }
165 }
166
167 return result;
168 }
169
170 FixedFunctionFlags fixedFunctionFlags() const override {
171 // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
172 // the helper's fixed function flags are appropriate.
173 return fHelper.fixedFunctionFlags();
174 }
175
176 DEFINE_OP_CLASS_ID
177
178private:
179 // For GrFillRectOp::MakeSet's use of addQuad
Robert Phillipsb97da532019-02-12 15:24:12 -0500180 friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(
181 GrRecordingContext*,
182 GrPaint&&,
183 GrAAType, const SkMatrix& viewMatrix,
Michael Ludwig69858532018-11-28 15:34:34 -0500184 const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
Robert Phillipsb97da532019-02-12 15:24:12 -0500185 const GrUserStencilSettings*);
Michael Ludwig69858532018-11-28 15:34:34 -0500186
Michael Ludwigc96fc372019-01-08 15:46:15 -0500187 void onPrepareDraws(Target* target) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500188 TRACE_EVENT0("skia", TRACE_FUNC);
189
190 using Domain = GrQuadPerEdgeAA::Domain;
191 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
192
Brian Salomon1d835422019-03-13 16:11:44 -0400193 VertexSpec vertexSpec(fDeviceQuads.quadType(), fColorType, fLocalQuads.quadType(),
194 fHelper.usesLocalCoords(), Domain::kNo, fHelper.aaType(),
195 fHelper.compatibleWithAlphaAsCoverage());
Michael Ludwigdcd48212019-01-08 15:28:57 -0500196 // Make sure that if the op thought it was a solid color, the vertex spec does not use
197 // local coords.
198 SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
Michael Ludwig69858532018-11-28 15:34:34 -0500199
Michael Ludwig467994d2018-12-03 14:58:31 +0000200 sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
Michael Ludwig69858532018-11-28 15:34:34 -0500201 size_t vertexSize = gp->vertexStride();
202
Brian Salomon12d22642019-01-29 14:38:50 -0500203 sk_sp<const GrBuffer> vbuffer;
Michael Ludwig69858532018-11-28 15:34:34 -0500204 int vertexOffsetInBuffer = 0;
205
206 // Fill the allocated vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500207 void* vdata = target->makeVertexSpace(
Michael Ludwigc96fc372019-01-08 15:46:15 -0500208 vertexSize, this->quadCount() * vertexSpec.verticesPerQuad(),
Michael Ludwig93aeba02018-12-21 09:50:31 -0500209 &vbuffer, &vertexOffsetInBuffer);
Michael Ludwig69858532018-11-28 15:34:34 -0500210 if (!vdata) {
211 SkDebugf("Could not allocate vertices\n");
212 return;
213 }
214
215 // vertices pointer advances through vdata based on Tessellate's return value
216 void* vertices = vdata;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500217 if (fHelper.isTrivial()) {
218 SkASSERT(fLocalQuads.count() == 0); // No local coords, so send an ignored dummy quad
Michael Ludwige9c57d32019-02-13 13:39:39 -0500219 static const GrPerspQuad kIgnoredLocal(SkRect::MakeEmpty());
220
Michael Ludwigdcd48212019-01-08 15:28:57 -0500221 for (int i = 0; i < this->quadCount(); ++i) {
222 const ColorAndAA& info = fDeviceQuads.metadata(i);
223 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
224 info.fColor, kIgnoredLocal, kEmptyDomain, info.fAAFlags);
225 }
226 } else {
227 SkASSERT(fLocalQuads.count() == fDeviceQuads.count());
228 for (int i = 0; i < this->quadCount(); ++i) {
229 const ColorAndAA& info = fDeviceQuads.metadata(i);
230 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
231 info.fColor, fLocalQuads[i], kEmptyDomain, info.fAAFlags);
232 }
Michael Ludwig69858532018-11-28 15:34:34 -0500233 }
234
235 // Configure the mesh for the vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500236 GrMesh* mesh = target->allocMeshes(1);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500237 if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, this->quadCount())) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500238 SkDebugf("Could not allocate indices\n");
239 return;
Michael Ludwig69858532018-11-28 15:34:34 -0500240 }
Brian Salomon12d22642019-01-29 14:38:50 -0500241 mesh->setVertexData(std::move(vbuffer), vertexOffsetInBuffer);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700242 target->recordDraw(std::move(gp), mesh);
243 }
Michael Ludwig69858532018-11-28 15:34:34 -0500244
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700245 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
246 fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
247 }
Michael Ludwig69858532018-11-28 15:34:34 -0500248
249 CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
250 TRACE_EVENT0("skia", TRACE_FUNC);
251 const auto* that = t->cast<FillRectOp>();
252
Michael Ludwig93aeba02018-12-21 09:50:31 -0500253 if ((fHelper.aaType() == GrAAType::kCoverage ||
254 that->fHelper.aaType() == GrAAType::kCoverage) &&
Michael Ludwigc96fc372019-01-08 15:46:15 -0500255 this->quadCount() + that->quadCount() > GrQuadPerEdgeAA::kNumAAQuadsInIndexBuffer) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500256 // This limit on batch size seems to help on Adreno devices
257 return CombineResult::kCannotCombine;
258 }
259
Michael Ludwigc96fc372019-01-08 15:46:15 -0500260 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
261 // ops together, so pass true as the last argument.
Michael Ludwig69858532018-11-28 15:34:34 -0500262 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
263 return CombineResult::kCannotCombine;
264 }
265
Michael Ludwigdcd48212019-01-08 15:28:57 -0500266 // If the paints were compatible, the trivial/solid-color state should be the same
267 SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
Michael Ludwig69858532018-11-28 15:34:34 -0500268
Michael Ludwigdcd48212019-01-08 15:28:57 -0500269 // If the processor sets are compatible, the two ops are always compatible; it just needs to
270 // adjust the state of the op to be the more general quad and aa types of the two ops and
271 // then concatenate the per-quad data.
Brian Salomon1d835422019-03-13 16:11:44 -0400272 fColorType = SkTMax(fColorType, that->fColorType);
Michael Ludwig69858532018-11-28 15:34:34 -0500273
274 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
275 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
276 // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
277 if (fHelper.aaType() == GrAAType::kNone && that->fHelper.aaType() == GrAAType::kCoverage) {
278 fHelper.setAAType(GrAAType::kCoverage);
279 }
280
Michael Ludwigc96fc372019-01-08 15:46:15 -0500281 fDeviceQuads.concat(that->fDeviceQuads);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500282 if (!fHelper.isTrivial()) {
283 fLocalQuads.concat(that->fLocalQuads);
284 }
Michael Ludwig69858532018-11-28 15:34:34 -0500285 return CombineResult::kMerged;
286 }
287
288 // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
289 // But since it's avoiding the op list management, it must update the op's bounds. This is only
290 // used with quad sets, which uses the same view matrix for each quad so this assumes that the
291 // device quad type of the new quad is the same as the op's.
Michael Ludwigc96fc372019-01-08 15:46:15 -0500292 void addQuad(const GrPerspQuad& deviceQuad, const GrPerspQuad& localQuad,
293 GrQuadType localQuadType, const SkPMColor4f& color, GrQuadAAFlags edgeAA,
294 GrAAType aaType) {
295 SkASSERT(deviceQuad.quadType() <= fDeviceQuads.quadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500296
297 // The new quad's aa type should be the same as the first quad's or none, except when the
298 // first quad's aa type was already downgraded to none, in which case the stored type must
299 // be lifted to back to the requested type.
300 if (aaType != fHelper.aaType()) {
301 if (aaType != GrAAType::kNone) {
302 // Original quad was downgraded to non-aa, lift back up to this quad's required type
303 SkASSERT(fHelper.aaType() == GrAAType::kNone);
304 fHelper.setAAType(aaType);
305 }
306 // else the new quad could have been downgraded but the other quads can't be, so don't
307 // reset the op's accumulated aa type.
308 }
309
Michael Ludwig69858532018-11-28 15:34:34 -0500310 // clear compatible won't need to be updated, since device quad type and paint is the same,
Brian Salomon1d835422019-03-13 16:11:44 -0400311 // but this quad has a new color, so maybe update color type
312 fColorType = SkTMax(fColorType, GrQuadPerEdgeAA::MinColorType(color));
Michael Ludwig69858532018-11-28 15:34:34 -0500313
314 // Update the bounds and add the quad to this op's storage
315 SkRect newBounds = this->bounds();
Michael Ludwigc96fc372019-01-08 15:46:15 -0500316 newBounds.joinPossiblyEmptyRect(deviceQuad.bounds(fDeviceQuads.quadType()));
Michael Ludwig69858532018-11-28 15:34:34 -0500317 this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
318 IsZeroArea::kNo);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500319 fDeviceQuads.push_back(deviceQuad, fDeviceQuads.quadType(), { color, edgeAA });
Michael Ludwigdcd48212019-01-08 15:28:57 -0500320 if (!fHelper.isTrivial()) {
321 fLocalQuads.push_back(localQuad, localQuadType);
322 }
Michael Ludwig69858532018-11-28 15:34:34 -0500323 }
324
Michael Ludwigc96fc372019-01-08 15:46:15 -0500325 int quadCount() const {
326 // Sanity check that the parallel arrays for quad properties all have the same size
Michael Ludwigdcd48212019-01-08 15:28:57 -0500327 SkASSERT(fDeviceQuads.count() == fLocalQuads.count() ||
328 (fLocalQuads.count() == 0 && fHelper.isTrivial()));
Michael Ludwigc96fc372019-01-08 15:46:15 -0500329 return fDeviceQuads.count();
330 }
331
332 struct ColorAndAA {
333 SkPMColor4f fColor;
334 GrQuadAAFlags fAAFlags;
335 };
Michael Ludwig69858532018-11-28 15:34:34 -0500336
337 Helper fHelper;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500338 GrTQuadList<ColorAndAA> fDeviceQuads;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500339 // No metadata attached to the local quads; this list is empty when local coords are not needed.
Michael Ludwigc96fc372019-01-08 15:46:15 -0500340 GrQuadList fLocalQuads;
Michael Ludwig69858532018-11-28 15:34:34 -0500341
Brian Salomon1d835422019-03-13 16:11:44 -0400342 ColorType fColorType;
Michael Ludwig69858532018-11-28 15:34:34 -0500343
Michael Ludwig69858532018-11-28 15:34:34 -0500344 typedef GrMeshDrawOp INHERITED;
345};
346
347} // anonymous namespace
348
349namespace GrFillRectOp {
350
Robert Phillipsb97da532019-02-12 15:24:12 -0500351std::unique_ptr<GrDrawOp> MakePerEdge(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500352 GrPaint&& paint,
353 GrAAType aaType,
354 GrQuadAAFlags edgeAA,
355 const SkMatrix& viewMatrix,
356 const SkRect& rect,
357 const GrUserStencilSettings* stencilSettings) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500358 GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500359 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500360 GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
361 GrPerspQuad(rect), GrQuadType::kRect);
Michael Ludwig69858532018-11-28 15:34:34 -0500362}
363
Robert Phillipsb97da532019-02-12 15:24:12 -0500364std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500365 GrPaint&& paint,
366 GrAAType aaType,
367 GrQuadAAFlags edgeAA,
368 const SkMatrix& viewMatrix,
369 const SkMatrix& localMatrix,
370 const SkRect& rect,
371 const GrUserStencilSettings* stencilSettings) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500372 GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500373 GrQuadType localQuadType = GrQuadTypeForTransformedRect(localMatrix);
374 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500375 GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
376 GrPerspQuad::MakeFromRect(rect, localMatrix), localQuadType);
Michael Ludwig69858532018-11-28 15:34:34 -0500377}
378
Robert Phillipsb97da532019-02-12 15:24:12 -0500379std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500380 GrPaint&& paint,
381 GrAAType aaType,
382 GrQuadAAFlags edgeAA,
383 const SkMatrix& viewMatrix,
384 const SkRect& rect,
385 const SkRect& localRect,
386 const GrUserStencilSettings* stencilSettings) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500387 GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500388 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500389 GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
390 GrPerspQuad(localRect), GrQuadType::kRect);
Michael Ludwig69858532018-11-28 15:34:34 -0500391}
392
Michael Ludwig009b92e2019-02-15 16:03:53 -0500393std::unique_ptr<GrDrawOp> MakePerEdgeQuad(GrRecordingContext* context,
394 GrPaint&& paint,
395 GrAAType aaType,
396 GrQuadAAFlags edgeAA,
397 const SkMatrix& viewMatrix,
398 const SkPoint quad[4],
399 const SkPoint localQuad[4],
400 const GrUserStencilSettings* stencilSettings) {
401 // With arbitrary quads, the quad types are limited to kStandard or kPerspective (unless we
402 // analyzed the points, but callers have more knowledge and should've just use the appropriate
403 // factory, so assume they can't be rectilinear or simpler)
404 GrQuadType deviceType = viewMatrix.hasPerspective() ? GrQuadType::kPerspective
405 : GrQuadType::kStandard;
406 return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
407 GrPerspQuad::MakeFromSkQuad(quad, viewMatrix), deviceType,
408 GrPerspQuad::MakeFromSkQuad(localQuad ? localQuad : quad,
409 SkMatrix::I()), GrQuadType::kStandard);
410}
411
Robert Phillipsb97da532019-02-12 15:24:12 -0500412std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -0500413 GrPaint&& paint,
414 GrAAType aaType,
415 const SkMatrix& viewMatrix,
416 const GrRenderTargetContext::QuadSetEntry quads[],
417 int cnt,
418 const GrUserStencilSettings* stencilSettings) {
419 // First make a draw op for the first quad in the set
420 SkASSERT(cnt > 0);
421 GrQuadType deviceQuadType = GrQuadTypeForTransformedRect(viewMatrix);
422
423 paint.setColor4f(quads[0].fColor);
424 std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500425 quads[0].fAAFlags, stencilSettings,
426 GrPerspQuad::MakeFromRect(quads[0].fRect, viewMatrix), deviceQuadType,
427 GrPerspQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix),
Michael Ludwig69858532018-11-28 15:34:34 -0500428 GrQuadTypeForTransformedRect(quads[0].fLocalMatrix));
429 auto* fillRects = op->cast<FillRectOp>();
430
431 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
432 for (int i = 1; i < cnt; ++i) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500433 GrPerspQuad deviceQuad = GrPerspQuad::MakeFromRect(quads[i].fRect, viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500434
435 GrAAType resolvedAA;
436 GrQuadAAFlags resolvedEdgeFlags;
437 GrResolveAATypeForQuad(aaType, quads[i].fAAFlags, deviceQuad, deviceQuadType,
438 &resolvedAA, &resolvedEdgeFlags);
439
Michael Ludwige9c57d32019-02-13 13:39:39 -0500440 fillRects->addQuad(deviceQuad,
441 GrPerspQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
Michael Ludwigc96fc372019-01-08 15:46:15 -0500442 GrQuadTypeForTransformedRect(quads[i].fLocalMatrix), quads[i].fColor,
443 resolvedEdgeFlags,resolvedAA);
Michael Ludwig69858532018-11-28 15:34:34 -0500444 }
445
446 return op;
447}
448
Robert Phillipsb97da532019-02-12 15:24:12 -0500449std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500450 GrPaint&& paint,
451 GrAAType aaType,
452 const SkMatrix& viewMatrix,
453 const SkRect& rect,
454 const GrUserStencilSettings* stencil) {
455 return MakePerEdge(context, std::move(paint), aaType,
456 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
457 viewMatrix, rect, stencil);
458}
459
Robert Phillipsb97da532019-02-12 15:24:12 -0500460std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500461 GrPaint&& paint,
462 GrAAType aaType,
463 const SkMatrix& viewMatrix,
464 const SkMatrix& localMatrix,
465 const SkRect& rect,
466 const GrUserStencilSettings* stencil) {
467 return MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
468 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
469 viewMatrix, localMatrix, rect, stencil);
470}
471
Robert Phillipsb97da532019-02-12 15:24:12 -0500472std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500473 GrPaint&& paint,
474 GrAAType aaType,
475 const SkMatrix& viewMatrix,
476 const SkRect& rect,
477 const SkRect& localRect,
478 const GrUserStencilSettings* stencil) {
479 return MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
480 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
481 viewMatrix, rect, localRect, stencil);
482}
483
Michael Ludwig69858532018-11-28 15:34:34 -0500484} // namespace GrFillRectOp
485
486#if GR_TEST_UTILS
487
488#include "GrDrawOpTest.h"
489#include "SkGr.h"
490
491GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
492 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
493 SkRect rect = GrTest::TestRect(random);
494
495 GrAAType aaType = GrAAType::kNone;
496 if (random->nextBool()) {
497 aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
498 }
499 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
500 : GrGetRandomStencil(random, context);
501
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 if (random->nextBool()) {
509 if (random->nextBool()) {
510 if (random->nextBool()) {
511 // Local matrix with a set op
512 uint32_t extraQuadCt = random->nextRangeU(1, 4);
513 SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
514 quads.push_back(
515 {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
516 GrTest::TestMatrixInvertible(random), aaFlags});
517 for (uint32_t i = 0; i < extraQuadCt; ++i) {
518 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
519 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
520 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
521 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
522 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
523
524 quads.push_back(
525 {GrTest::TestRect(random),
526 SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
527 GrTest::TestMatrixInvertible(random), aaFlags});
528 }
529
530 return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
531 quads.begin(), quads.count(), stencil);
532 } else {
533 // Single local matrix
534 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500535 return GrFillRectOp::MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
536 aaFlags, viewMatrix, localMatrix,
537 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500538 }
539 } else {
540 // Pass local rect directly
541 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500542 return GrFillRectOp::MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
543 aaFlags, viewMatrix, rect, localRect,
544 stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500545 }
546 } else {
547 // The simplest constructor
Michael Ludwig72ab3462018-12-10 12:43:36 -0500548 return GrFillRectOp::MakePerEdge(context, std::move(paint), aaType, aaFlags, viewMatrix,
549 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500550 }
551}
552
553#endif