blob: 3a6a492777261aaaa045322dd147d2dddac39e81 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/ops/GrFillRectOp.h"
Michael Ludwig69858532018-11-28 15:34:34 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkMatrix.h"
11#include "include/core/SkRect.h"
12#include "src/gpu/GrCaps.h"
13#include "src/gpu/GrGeometryProcessor.h"
14#include "src/gpu/GrPaint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/gpu/SkGr.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040016#include "src/gpu/geometry/GrQuad.h"
Michael Ludwig425eb452019-06-27 10:13:27 -040017#include "src/gpu/geometry/GrQuadBuffer.h"
Michael Ludwig0f809022019-06-04 09:14:37 -040018#include "src/gpu/geometry/GrQuadUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
20#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
21#include "src/gpu/glsl/GrGLSLVarying.h"
22#include "src/gpu/ops/GrMeshDrawOp.h"
23#include "src/gpu/ops/GrQuadPerEdgeAA.h"
24#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Michael Ludwig69858532018-11-28 15:34:34 -050025
26namespace {
27
28using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
29using ColorType = GrQuadPerEdgeAA::ColorType;
30
Michael Ludwigc96fc372019-01-08 15:46:15 -050031#ifdef SK_DEBUG
Michael Ludwigde4c58c2019-06-04 09:12:59 -040032static SkString dump_quad_info(int index, const GrQuad& deviceQuad,
33 const GrQuad& localQuad, const SkPMColor4f& color,
Michael Ludwigc96fc372019-01-08 15:46:15 -050034 GrQuadAAFlags aaFlags) {
35 SkString str;
36 str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
37 " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
38 "(%.2f, %.2f, %.2f)],\n"
39 " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
40 "(%.2f, %.2f, %.2f)]\n",
41 index, color.fR, color.fG, color.fB, color.fA,
42 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
43 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
44 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
45 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
46 deviceQuad.x(0), deviceQuad.y(0), deviceQuad.w(0),
47 deviceQuad.x(1), deviceQuad.y(1), deviceQuad.w(1),
48 deviceQuad.x(2), deviceQuad.y(2), deviceQuad.w(2),
49 deviceQuad.x(3), deviceQuad.y(3), deviceQuad.w(3),
50 localQuad.x(0), localQuad.y(0), localQuad.w(0),
51 localQuad.x(1), localQuad.y(1), localQuad.w(1),
52 localQuad.x(2), localQuad.y(2), localQuad.w(2),
53 localQuad.x(3), localQuad.y(3), localQuad.w(3));
54 return str;
55}
56#endif
Michael Ludwig69858532018-11-28 15:34:34 -050057
Michael Ludwig69858532018-11-28 15:34:34 -050058class FillRectOp final : public GrMeshDrawOp {
59private:
60 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
61
62public:
Robert Phillipsb97da532019-02-12 15:24:12 -050063 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -050064 GrPaint&& paint,
65 GrAAType aaType,
66 GrQuadAAFlags edgeAA,
67 const GrUserStencilSettings* stencilSettings,
Michael Ludwigde4c58c2019-06-04 09:12:59 -040068 const GrQuad& deviceQuad,
69 const GrQuad& localQuad) {
Michael Ludwig69858532018-11-28 15:34:34 -050070 // Clean up deviations between aaType and edgeAA
Michael Ludwig0f809022019-06-04 09:14:37 -040071 GrQuadUtils::ResolveAAType(aaType, edgeAA, deviceQuad, &aaType, &edgeAA);
Michael Ludwigdcd48212019-01-08 15:28:57 -050072 return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
Michael Ludwig41f395d2019-05-23 13:59:45 -040073 stencilSettings, deviceQuad, localQuad);
Michael Ludwig69858532018-11-28 15:34:34 -050074 }
75
Michael Ludwigdcd48212019-01-08 15:28:57 -050076 // aaType is passed to Helper in the initializer list, so incongruities between aaType and
77 // edgeFlags must be resolved prior to calling this constructor.
78 FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
79 GrQuadAAFlags edgeFlags, const GrUserStencilSettings* stencil,
Michael Ludwigde4c58c2019-06-04 09:12:59 -040080 const GrQuad& deviceQuad, const GrQuad& localQuad)
Michael Ludwig69858532018-11-28 15:34:34 -050081 : INHERITED(ClassID())
Michael Ludwig425eb452019-06-27 10:13:27 -040082 , fHelper(args, aaType, stencil)
83 , fQuads(1, !fHelper.isTrivial()) {
84 // Conservatively keep track of the local coordinates; it may be that the paint doesn't
85 // need them after analysis is finished. If the paint is known to be solid up front they
86 // can be skipped entirely.
87 fQuads.append(deviceQuad, { paintColor, edgeFlags },
88 fHelper.isTrivial() ? nullptr : &localQuad);
Michael Ludwig41f395d2019-05-23 13:59:45 -040089 this->setBounds(deviceQuad.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
Greg Daniel5faf4742019-10-01 15:14:44 -040090 IsHairline::kNo);
Michael Ludwig69858532018-11-28 15:34:34 -050091 }
92
93 const char* name() const override { return "FillRectOp"; }
94
Chris Dalton1706cbf2019-05-21 19:35:29 -060095 void visitProxies(const VisitProxyFunc& func) const override {
Michael Ludwig69858532018-11-28 15:34:34 -050096 return fHelper.visitProxies(func);
97 }
98
99#ifdef SK_DEBUG
100 SkString dumpInfo() const override {
101 SkString str;
Michael Ludwig425eb452019-06-27 10:13:27 -0400102 str.appendf("# draws: %u\n", fQuads.count());
Michael Ludwig69858532018-11-28 15:34:34 -0500103 str.appendf("Device quad type: %u, local quad type: %u\n",
Michael Ludwig425eb452019-06-27 10:13:27 -0400104 (uint32_t) fQuads.deviceQuadType(), (uint32_t) fQuads.localQuadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500105 str += fHelper.dumpInfo();
Michael Ludwig425eb452019-06-27 10:13:27 -0400106 int i = 0;
107 auto iter = fQuads.iterator();
108 while(iter.next()) {
109 const ColorAndAA& info = iter.metadata();
110 str += dump_quad_info(i, iter.deviceQuad(), iter.localQuad(),
111 info.fColor, info.fAAFlags);
112 i++;
Michael Ludwig69858532018-11-28 15:34:34 -0500113 }
114 str += INHERITED::dumpInfo();
115 return str;
116 }
117#endif
118
Chris Dalton6ce447a2019-06-23 18:07:38 -0600119 GrProcessorSet::Analysis finalize(
120 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
121 GrClampType clampType) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500122 // Initialize aggregate color analysis with the first quad's color (which always exists)
Michael Ludwig425eb452019-06-27 10:13:27 -0400123 auto iter = fQuads.metadata();
124 SkAssertResult(iter.next());
125 GrProcessorAnalysisColor quadColors(iter->fColor);
Michael Ludwig69858532018-11-28 15:34:34 -0500126 // Then combine the colors of any additional quads (e.g. from MakeSet)
Michael Ludwig425eb452019-06-27 10:13:27 -0400127 while(iter.next()) {
128 quadColors = GrProcessorAnalysisColor::Combine(quadColors, iter->fColor);
Michael Ludwigca91e1f2018-12-10 10:44:44 -0500129 if (quadColors.isUnknown()) {
130 // No point in accumulating additional starting colors, combining cannot make it
131 // less unknown.
132 break;
133 }
Michael Ludwig69858532018-11-28 15:34:34 -0500134 }
Michael Ludwig72ab3462018-12-10 12:43:36 -0500135
136 // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
137 // then the coverage is always 1.0, so specify kNone for more optimal blending.
138 GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
139 GrProcessorAnalysisCoverage::kSingleChannel :
140 GrProcessorAnalysisCoverage::kNone;
Brian Osman5ced0bf2019-03-15 10:15:29 -0400141 auto result = fHelper.finalizeProcessors(
Chris Dalton6ce447a2019-06-23 18:07:38 -0600142 caps, clip, hasMixedSampledCoverage, clampType, coverage, &quadColors);
Michael Ludwig69858532018-11-28 15:34:34 -0500143 // If there is a constant color after analysis, that means all of the quads should be set
144 // to the same color (even if they started out with different colors).
Michael Ludwig425eb452019-06-27 10:13:27 -0400145 iter = fQuads.metadata();
Michael Ludwig69858532018-11-28 15:34:34 -0500146 SkPMColor4f colorOverride;
147 if (quadColors.isConstant(&colorOverride)) {
Brian Osman8fa7ab42019-03-18 10:22:42 -0400148 fColorType = GrQuadPerEdgeAA::MinColorType(colorOverride, clampType, caps);
Michael Ludwig425eb452019-06-27 10:13:27 -0400149 while(iter.next()) {
150 iter->fColor = colorOverride;
Michael Ludwig69858532018-11-28 15:34:34 -0500151 }
Brian Osman8fa7ab42019-03-18 10:22:42 -0400152 } else {
153 // Otherwise compute the color type needed as the max over all quads.
154 fColorType = ColorType::kNone;
Michael Ludwig425eb452019-06-27 10:13:27 -0400155 while(iter.next()) {
Brian Osman8fa7ab42019-03-18 10:22:42 -0400156 fColorType = SkTMax(fColorType,
Michael Ludwig425eb452019-06-27 10:13:27 -0400157 GrQuadPerEdgeAA::MinColorType(iter->fColor, clampType, caps));
Brian Osman8fa7ab42019-03-18 10:22:42 -0400158 }
Michael Ludwig69858532018-11-28 15:34:34 -0500159 }
Brian Salomon41f9c3c2019-03-25 11:06:12 -0400160 // Most SkShaders' FPs multiply their calculated color by the paint color or alpha. We want
161 // to use ColorType::kNone to optimize out that multiply. However, if there are no color
162 // FPs then were really writing a special shader for white rectangles and not saving any
163 // multiples. So in that case use bytes to avoid the extra shader (and possibly work around
164 // an ANGLE issue: crbug.com/942565).
165 if (fColorType == ColorType::kNone && !result.hasColorFragmentProcessor()) {
166 fColorType = ColorType::kByte;
167 }
Michael Ludwig69858532018-11-28 15:34:34 -0500168
169 return result;
170 }
171
172 FixedFunctionFlags fixedFunctionFlags() const override {
173 // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
174 // the helper's fixed function flags are appropriate.
175 return fHelper.fixedFunctionFlags();
176 }
177
178 DEFINE_OP_CLASS_ID
179
180private:
181 // For GrFillRectOp::MakeSet's use of addQuad
Robert Phillipsb97da532019-02-12 15:24:12 -0500182 friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(
183 GrRecordingContext*,
184 GrPaint&&,
185 GrAAType, const SkMatrix& viewMatrix,
Michael Ludwig69858532018-11-28 15:34:34 -0500186 const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
Robert Phillipsb97da532019-02-12 15:24:12 -0500187 const GrUserStencilSettings*);
Michael Ludwig69858532018-11-28 15:34:34 -0500188
Michael Ludwigc96fc372019-01-08 15:46:15 -0500189 void onPrepareDraws(Target* target) override {
Brian Salomon5f394272019-07-02 14:07:49 -0400190 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Michael Ludwig69858532018-11-28 15:34:34 -0500191
192 using Domain = GrQuadPerEdgeAA::Domain;
193 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
194
Robert Phillipsc554dcf2019-10-28 11:43:55 -0400195 auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(fHelper.aaType(),
196 fQuads.count());
197
Michael Ludwig425eb452019-06-27 10:13:27 -0400198 VertexSpec vertexSpec(fQuads.deviceQuadType(), fColorType, fQuads.localQuadType(),
Brian Salomon1d835422019-03-13 16:11:44 -0400199 fHelper.usesLocalCoords(), Domain::kNo, fHelper.aaType(),
Robert Phillipsc554dcf2019-10-28 11:43:55 -0400200 fHelper.compatibleWithCoverageAsAlpha(), indexBufferOption);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500201 // Make sure that if the op thought it was a solid color, the vertex spec does not use
202 // local coords.
203 SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
Michael Ludwig69858532018-11-28 15:34:34 -0500204
Michael Ludwig467994d2018-12-03 14:58:31 +0000205 sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
Michael Ludwig69858532018-11-28 15:34:34 -0500206 size_t vertexSize = gp->vertexStride();
207
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400208 sk_sp<const GrBuffer> vertexBuffer;
Michael Ludwig69858532018-11-28 15:34:34 -0500209 int vertexOffsetInBuffer = 0;
210
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400211 const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
212
Michael Ludwig69858532018-11-28 15:34:34 -0500213 // Fill the allocated vertex data
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400214 void* vdata = target->makeVertexSpace(vertexSize, totalNumVertices,
215 &vertexBuffer, &vertexOffsetInBuffer);
Michael Ludwig69858532018-11-28 15:34:34 -0500216 if (!vdata) {
217 SkDebugf("Could not allocate vertices\n");
218 return;
219 }
220
221 // vertices pointer advances through vdata based on Tessellate's return value
222 void* vertices = vdata;
Michael Ludwig425eb452019-06-27 10:13:27 -0400223 auto iter = fQuads.iterator();
224 while(iter.next()) {
225 // All entries should have local coords, or no entries should have local coords,
226 // matching !helper.isTrivial() (which is more conservative than helper.usesLocalCoords)
227 SkASSERT(iter.isLocalValid() != fHelper.isTrivial());
228 auto info = iter.metadata();
229 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, iter.deviceQuad(),
230 info.fColor, iter.localQuad(), kEmptyDomain, info.fAAFlags);
Michael Ludwig69858532018-11-28 15:34:34 -0500231 }
232
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400233 sk_sp<const GrBuffer> indexBuffer;
234 if (vertexSpec.needsIndexBuffer()) {
235 indexBuffer = GrQuadPerEdgeAA::GetIndexBuffer(target, vertexSpec.indexBufferOption());
236 if (!indexBuffer) {
237 SkDebugf("Could not allocate indices\n");
238 return;
239 }
240 }
241
Michael Ludwig69858532018-11-28 15:34:34 -0500242 // Configure the mesh for the vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500243 GrMesh* mesh = target->allocMeshes(1);
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400244 GrQuadPerEdgeAA::ConfigureMesh(mesh, vertexSpec, 0, fQuads.count(), totalNumVertices,
245 std::move(vertexBuffer), std::move(indexBuffer),
246 vertexOffsetInBuffer);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700247 target->recordDraw(std::move(gp), mesh);
248 }
Michael Ludwig69858532018-11-28 15:34:34 -0500249
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700250 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
251 fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
252 }
Michael Ludwig69858532018-11-28 15:34:34 -0500253
254 CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
Brian Salomon5f394272019-07-02 14:07:49 -0400255 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Michael Ludwig69858532018-11-28 15:34:34 -0500256 const auto* that = t->cast<FillRectOp>();
257
Robert Phillipsb69001f2019-10-29 12:16:35 -0400258 bool upgradeToCoverageAAOnMerge = false;
259 if (fHelper.aaType() != that->fHelper.aaType()) {
Robert Phillipsbbd459d2019-10-29 14:40:03 -0400260 if (!CanUpgradeAAOnMerge(fHelper.aaType(), that->fHelper.aaType())) {
Robert Phillipsb69001f2019-10-29 12:16:35 -0400261 return CombineResult::kCannotCombine;
262 }
263 upgradeToCoverageAAOnMerge = true;
264 }
265
Robert Phillipsbbd459d2019-10-29 14:40:03 -0400266 if (CombinedQuadCountWillOverflow(fHelper.aaType(), upgradeToCoverageAAOnMerge,
267 fQuads.count() + that->fQuads.count())) {
268 return CombineResult::kCannotCombine;
Michael Ludwig93aeba02018-12-21 09:50:31 -0500269 }
270
Michael Ludwigc96fc372019-01-08 15:46:15 -0500271 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
272 // ops together, so pass true as the last argument.
Michael Ludwig69858532018-11-28 15:34:34 -0500273 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
274 return CombineResult::kCannotCombine;
275 }
276
Michael Ludwigdcd48212019-01-08 15:28:57 -0500277 // If the paints were compatible, the trivial/solid-color state should be the same
278 SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
Michael Ludwig69858532018-11-28 15:34:34 -0500279
Michael Ludwigdcd48212019-01-08 15:28:57 -0500280 // If the processor sets are compatible, the two ops are always compatible; it just needs to
281 // adjust the state of the op to be the more general quad and aa types of the two ops and
282 // then concatenate the per-quad data.
Brian Salomon1d835422019-03-13 16:11:44 -0400283 fColorType = SkTMax(fColorType, that->fColorType);
Michael Ludwig69858532018-11-28 15:34:34 -0500284
285 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
286 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
287 // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
Robert Phillipsb69001f2019-10-29 12:16:35 -0400288 if (upgradeToCoverageAAOnMerge) {
Michael Ludwig69858532018-11-28 15:34:34 -0500289 fHelper.setAAType(GrAAType::kCoverage);
290 }
291
Michael Ludwig425eb452019-06-27 10:13:27 -0400292 fQuads.concat(that->fQuads);
Michael Ludwig69858532018-11-28 15:34:34 -0500293 return CombineResult::kMerged;
294 }
295
296 // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
297 // But since it's avoiding the op list management, it must update the op's bounds. This is only
298 // used with quad sets, which uses the same view matrix for each quad so this assumes that the
299 // device quad type of the new quad is the same as the op's.
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400300 void addQuad(const GrQuad& deviceQuad, const GrQuad& localQuad,
Michael Ludwig41f395d2019-05-23 13:59:45 -0400301 const SkPMColor4f& color, GrQuadAAFlags edgeAA, GrAAType aaType) {
Michael Ludwig69858532018-11-28 15:34:34 -0500302 // The new quad's aa type should be the same as the first quad's or none, except when the
303 // first quad's aa type was already downgraded to none, in which case the stored type must
304 // be lifted to back to the requested type.
305 if (aaType != fHelper.aaType()) {
306 if (aaType != GrAAType::kNone) {
307 // Original quad was downgraded to non-aa, lift back up to this quad's required type
308 SkASSERT(fHelper.aaType() == GrAAType::kNone);
309 fHelper.setAAType(aaType);
310 }
311 // else the new quad could have been downgraded but the other quads can't be, so don't
312 // reset the op's accumulated aa type.
313 }
314
Michael Ludwig69858532018-11-28 15:34:34 -0500315 // Update the bounds and add the quad to this op's storage
316 SkRect newBounds = this->bounds();
Michael Ludwig41f395d2019-05-23 13:59:45 -0400317 newBounds.joinPossiblyEmptyRect(deviceQuad.bounds());
Michael Ludwig69858532018-11-28 15:34:34 -0500318 this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
Greg Daniel5faf4742019-10-01 15:14:44 -0400319 IsHairline::kNo);
Michael Ludwig425eb452019-06-27 10:13:27 -0400320 fQuads.append(deviceQuad, { color, edgeAA }, fHelper.isTrivial() ? nullptr : &localQuad);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500321 }
322
323 struct ColorAndAA {
324 SkPMColor4f fColor;
325 GrQuadAAFlags fAAFlags;
326 };
Michael Ludwig69858532018-11-28 15:34:34 -0500327
328 Helper fHelper;
Michael Ludwig425eb452019-06-27 10:13:27 -0400329 GrQuadBuffer<ColorAndAA> fQuads;
Michael Ludwig69858532018-11-28 15:34:34 -0500330
Brian Salomon1d835422019-03-13 16:11:44 -0400331 ColorType fColorType;
Michael Ludwig69858532018-11-28 15:34:34 -0500332
Michael Ludwig69858532018-11-28 15:34:34 -0500333 typedef GrMeshDrawOp INHERITED;
334};
335
336} // anonymous namespace
337
338namespace GrFillRectOp {
339
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400340std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
341 GrPaint&& paint,
342 GrAAType aaType,
343 GrQuadAAFlags aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400344 const GrQuad& deviceQuad,
345 const GrQuad& localQuad,
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400346 const GrUserStencilSettings* stencil) {
Michael Ludwigd9f917b2019-05-24 12:57:55 -0400347 return FillRectOp::Make(context, std::move(paint), aaType, aaFlags, stencil,
348 deviceQuad, localQuad);
349}
350
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400351std::unique_ptr<GrDrawOp> MakeNonAARect(GrRecordingContext* context,
352 GrPaint&& paint,
353 const SkMatrix& view,
354 const SkRect& rect,
355 const GrUserStencilSettings* stencil) {
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400356 return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, GrQuadAAFlags::kNone,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400357 stencil, GrQuad::MakeFromRect(rect, view), GrQuad(rect));
Michael Ludwig009b92e2019-02-15 16:03:53 -0500358}
359
Robert Phillipsb97da532019-02-12 15:24:12 -0500360std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -0500361 GrPaint&& paint,
362 GrAAType aaType,
363 const SkMatrix& viewMatrix,
364 const GrRenderTargetContext::QuadSetEntry quads[],
365 int cnt,
366 const GrUserStencilSettings* stencilSettings) {
367 // First make a draw op for the first quad in the set
368 SkASSERT(cnt > 0);
Michael Ludwig69858532018-11-28 15:34:34 -0500369
370 paint.setColor4f(quads[0].fColor);
371 std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500372 quads[0].fAAFlags, stencilSettings,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400373 GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
374 GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix));
Michael Ludwig69858532018-11-28 15:34:34 -0500375 auto* fillRects = op->cast<FillRectOp>();
376
377 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
378 for (int i = 1; i < cnt; ++i) {
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400379 GrQuad deviceQuad = GrQuad::MakeFromRect(quads[i].fRect, viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500380
381 GrAAType resolvedAA;
382 GrQuadAAFlags resolvedEdgeFlags;
Michael Ludwig0f809022019-06-04 09:14:37 -0400383 GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, deviceQuad,
384 &resolvedAA, &resolvedEdgeFlags);
Michael Ludwig69858532018-11-28 15:34:34 -0500385
Michael Ludwige9c57d32019-02-13 13:39:39 -0500386 fillRects->addQuad(deviceQuad,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400387 GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
Michael Ludwig41f395d2019-05-23 13:59:45 -0400388 quads[i].fColor, resolvedEdgeFlags,resolvedAA);
Michael Ludwig69858532018-11-28 15:34:34 -0500389 }
390
391 return op;
392}
393
394} // namespace GrFillRectOp
395
396#if GR_TEST_UTILS
397
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500398#include "src/gpu/GrDrawOpTest.h"
399#include "src/gpu/SkGr.h"
Michael Ludwig69858532018-11-28 15:34:34 -0500400
401GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
402 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
403 SkRect rect = GrTest::TestRect(random);
404
405 GrAAType aaType = GrAAType::kNone;
406 if (random->nextBool()) {
Chris Dalton6ce447a2019-06-23 18:07:38 -0600407 aaType = (numSamples > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
Michael Ludwig69858532018-11-28 15:34:34 -0500408 }
409 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
410 : GrGetRandomStencil(random, context);
411
412 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
413 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
414 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
415 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
416 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
417
418 if (random->nextBool()) {
419 if (random->nextBool()) {
420 if (random->nextBool()) {
421 // Local matrix with a set op
422 uint32_t extraQuadCt = random->nextRangeU(1, 4);
423 SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
424 quads.push_back(
425 {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
426 GrTest::TestMatrixInvertible(random), aaFlags});
427 for (uint32_t i = 0; i < extraQuadCt; ++i) {
428 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
429 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
430 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
431 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
432 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
433
434 quads.push_back(
435 {GrTest::TestRect(random),
436 SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
437 GrTest::TestMatrixInvertible(random), aaFlags});
438 }
439
440 return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
441 quads.begin(), quads.count(), stencil);
442 } else {
443 // Single local matrix
444 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400445 return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400446 GrQuad::MakeFromRect(rect, viewMatrix),
447 GrQuad::MakeFromRect(rect, localMatrix), stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500448 }
449 } else {
450 // Pass local rect directly
451 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400452 return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400453 GrQuad::MakeFromRect(rect, viewMatrix),
454 GrQuad(localRect), stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500455 }
456 } else {
457 // The simplest constructor
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400458 return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400459 GrQuad::MakeFromRect(rect, viewMatrix),
460 GrQuad(rect), stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500461 }
462}
463
464#endif