blob: 3433dc9661a550e7fa175aeb2c4e68090ebe7331 [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 Ludwigd17e05a2019-06-04 09:10:34 -040017#include "src/gpu/geometry/GrQuadList.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
19#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
20#include "src/gpu/glsl/GrGLSLVarying.h"
21#include "src/gpu/ops/GrMeshDrawOp.h"
22#include "src/gpu/ops/GrQuadPerEdgeAA.h"
23#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Michael Ludwig69858532018-11-28 15:34:34 -050024
25namespace {
26
27using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
28using ColorType = GrQuadPerEdgeAA::ColorType;
29
Michael Ludwigc96fc372019-01-08 15:46:15 -050030#ifdef SK_DEBUG
Michael Ludwigde4c58c2019-06-04 09:12:59 -040031static SkString dump_quad_info(int index, const GrQuad& deviceQuad,
32 const GrQuad& localQuad, const SkPMColor4f& color,
Michael Ludwigc96fc372019-01-08 15:46:15 -050033 GrQuadAAFlags aaFlags) {
34 SkString str;
35 str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
36 " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
37 "(%.2f, %.2f, %.2f)],\n"
38 " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
39 "(%.2f, %.2f, %.2f)]\n",
40 index, color.fR, color.fG, color.fB, color.fA,
41 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
42 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
43 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
44 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
45 deviceQuad.x(0), deviceQuad.y(0), deviceQuad.w(0),
46 deviceQuad.x(1), deviceQuad.y(1), deviceQuad.w(1),
47 deviceQuad.x(2), deviceQuad.y(2), deviceQuad.w(2),
48 deviceQuad.x(3), deviceQuad.y(3), deviceQuad.w(3),
49 localQuad.x(0), localQuad.y(0), localQuad.w(0),
50 localQuad.x(1), localQuad.y(1), localQuad.w(1),
51 localQuad.x(2), localQuad.y(2), localQuad.w(2),
52 localQuad.x(3), localQuad.y(3), localQuad.w(3));
53 return str;
54}
55#endif
Michael Ludwig69858532018-11-28 15:34:34 -050056
Michael Ludwig69858532018-11-28 15:34:34 -050057class FillRectOp final : public GrMeshDrawOp {
58private:
59 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
60
61public:
Robert Phillipsb97da532019-02-12 15:24:12 -050062 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -050063 GrPaint&& paint,
64 GrAAType aaType,
65 GrQuadAAFlags edgeAA,
66 const GrUserStencilSettings* stencilSettings,
Michael Ludwigde4c58c2019-06-04 09:12:59 -040067 const GrQuad& deviceQuad,
68 const GrQuad& localQuad) {
Michael Ludwig69858532018-11-28 15:34:34 -050069 // Clean up deviations between aaType and edgeAA
Michael Ludwig41f395d2019-05-23 13:59:45 -040070 GrResolveAATypeForQuad(aaType, edgeAA, deviceQuad, &aaType, &edgeAA);
Michael Ludwigdcd48212019-01-08 15:28:57 -050071 return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
Michael Ludwig41f395d2019-05-23 13:59:45 -040072 stencilSettings, deviceQuad, localQuad);
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 Ludwigde4c58c2019-06-04 09:12:59 -040079 const GrQuad& deviceQuad, const GrQuad& localQuad)
Michael Ludwig69858532018-11-28 15:34:34 -050080 : INHERITED(ClassID())
Brian Osman8fa7ab42019-03-18 10:22:42 -040081 , fHelper(args, aaType, stencil) {
Michael Ludwig69858532018-11-28 15:34:34 -050082 // The color stored with the quad is the clear color if a scissor-clear is decided upon
83 // when executing the op.
Michael Ludwig41f395d2019-05-23 13:59:45 -040084 fDeviceQuads.push_back(deviceQuad, { paintColor, edgeFlags });
Michael Ludwigdcd48212019-01-08 15:28:57 -050085
86 if (!fHelper.isTrivial()) {
87 // Conservatively keep track of the local coordinates; it may be that the paint doesn't
88 // need them after analysis is finished. If the paint is known to be solid up front they
89 // can be skipped entirely.
Michael Ludwig41f395d2019-05-23 13:59:45 -040090 fLocalQuads.push_back(localQuad);
Michael Ludwigdcd48212019-01-08 15:28:57 -050091 }
Michael Ludwig41f395d2019-05-23 13:59:45 -040092 this->setBounds(deviceQuad.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
93 IsZeroArea::kNo);
Michael Ludwig69858532018-11-28 15:34:34 -050094 }
95
96 const char* name() const override { return "FillRectOp"; }
97
Chris Dalton1706cbf2019-05-21 19:35:29 -060098 void visitProxies(const VisitProxyFunc& func) const override {
Michael Ludwig69858532018-11-28 15:34:34 -050099 return fHelper.visitProxies(func);
100 }
101
102#ifdef SK_DEBUG
103 SkString dumpInfo() const override {
104 SkString str;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500105 str.appendf("# draws: %u\n", this->quadCount());
Michael Ludwig69858532018-11-28 15:34:34 -0500106 str.appendf("Device quad type: %u, local quad type: %u\n",
Michael Ludwigc96fc372019-01-08 15:46:15 -0500107 (uint32_t) fDeviceQuads.quadType(), (uint32_t) fLocalQuads.quadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500108 str += fHelper.dumpInfo();
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400109 GrQuad device, local;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500110 for (int i = 0; i < this->quadCount(); i++) {
111 device = fDeviceQuads[i];
112 const ColorAndAA& info = fDeviceQuads.metadata(i);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500113 if (!fHelper.isTrivial()) {
114 local = fLocalQuads[i];
115 }
Michael Ludwigc96fc372019-01-08 15:46:15 -0500116 str += dump_quad_info(i, device, local, info.fColor, info.fAAFlags);
Michael Ludwig69858532018-11-28 15:34:34 -0500117 }
118 str += INHERITED::dumpInfo();
119 return str;
120 }
121#endif
122
Brian Osman5ced0bf2019-03-15 10:15:29 -0400123 GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
124 GrFSAAType fsaaType, GrClampType clampType) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500125 // 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;
Brian Osman5ced0bf2019-03-15 10:15:29 -0400144 auto result = fHelper.finalizeProcessors(
145 caps, clip, fsaaType, clampType, 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)) {
Brian Osman8fa7ab42019-03-18 10:22:42 -0400150 fColorType = GrQuadPerEdgeAA::MinColorType(colorOverride, clampType, caps);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500151 for (int i = 0; i < this->quadCount(); ++i) {
152 fDeviceQuads.metadata(i).fColor = colorOverride;
Michael Ludwig69858532018-11-28 15:34:34 -0500153 }
Brian Osman8fa7ab42019-03-18 10:22:42 -0400154 } else {
155 // Otherwise compute the color type needed as the max over all quads.
156 fColorType = ColorType::kNone;
157 for (int i = 0; i < this->quadCount(); ++i) {
158 SkPMColor4f* color = &fDeviceQuads.metadata(i).fColor;
159 fColorType = SkTMax(fColorType,
160 GrQuadPerEdgeAA::MinColorType(*color, clampType, caps));
161 }
Michael Ludwig69858532018-11-28 15:34:34 -0500162 }
Brian Salomon41f9c3c2019-03-25 11:06:12 -0400163 // Most SkShaders' FPs multiply their calculated color by the paint color or alpha. We want
164 // to use ColorType::kNone to optimize out that multiply. However, if there are no color
165 // FPs then were really writing a special shader for white rectangles and not saving any
166 // multiples. So in that case use bytes to avoid the extra shader (and possibly work around
167 // an ANGLE issue: crbug.com/942565).
168 if (fColorType == ColorType::kNone && !result.hasColorFragmentProcessor()) {
169 fColorType = ColorType::kByte;
170 }
Michael Ludwig69858532018-11-28 15:34:34 -0500171
172 return result;
173 }
174
175 FixedFunctionFlags fixedFunctionFlags() const override {
176 // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
177 // the helper's fixed function flags are appropriate.
178 return fHelper.fixedFunctionFlags();
179 }
180
181 DEFINE_OP_CLASS_ID
182
183private:
184 // For GrFillRectOp::MakeSet's use of addQuad
Robert Phillipsb97da532019-02-12 15:24:12 -0500185 friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(
186 GrRecordingContext*,
187 GrPaint&&,
188 GrAAType, const SkMatrix& viewMatrix,
Michael Ludwig69858532018-11-28 15:34:34 -0500189 const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
Robert Phillipsb97da532019-02-12 15:24:12 -0500190 const GrUserStencilSettings*);
Michael Ludwig69858532018-11-28 15:34:34 -0500191
Michael Ludwigc96fc372019-01-08 15:46:15 -0500192 void onPrepareDraws(Target* target) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500193 TRACE_EVENT0("skia", TRACE_FUNC);
194
195 using Domain = GrQuadPerEdgeAA::Domain;
196 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
197
Brian Salomon1d835422019-03-13 16:11:44 -0400198 VertexSpec vertexSpec(fDeviceQuads.quadType(), fColorType, fLocalQuads.quadType(),
199 fHelper.usesLocalCoords(), Domain::kNo, fHelper.aaType(),
Brian Osman605c6d52019-03-15 12:10:35 -0400200 fHelper.compatibleWithCoverageAsAlpha());
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
Brian Salomon12d22642019-01-29 14:38:50 -0500208 sk_sp<const GrBuffer> vbuffer;
Michael Ludwig69858532018-11-28 15:34:34 -0500209 int vertexOffsetInBuffer = 0;
210
211 // Fill the allocated vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500212 void* vdata = target->makeVertexSpace(
Michael Ludwigc96fc372019-01-08 15:46:15 -0500213 vertexSize, this->quadCount() * vertexSpec.verticesPerQuad(),
Michael Ludwig93aeba02018-12-21 09:50:31 -0500214 &vbuffer, &vertexOffsetInBuffer);
Michael Ludwig69858532018-11-28 15:34:34 -0500215 if (!vdata) {
216 SkDebugf("Could not allocate vertices\n");
217 return;
218 }
219
220 // vertices pointer advances through vdata based on Tessellate's return value
221 void* vertices = vdata;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500222 if (fHelper.isTrivial()) {
223 SkASSERT(fLocalQuads.count() == 0); // No local coords, so send an ignored dummy quad
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400224 static const GrQuad kIgnoredLocal(SkRect::MakeEmpty());
Michael Ludwige9c57d32019-02-13 13:39:39 -0500225
Michael Ludwigdcd48212019-01-08 15:28:57 -0500226 for (int i = 0; i < this->quadCount(); ++i) {
227 const ColorAndAA& info = fDeviceQuads.metadata(i);
228 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
229 info.fColor, kIgnoredLocal, kEmptyDomain, info.fAAFlags);
230 }
231 } else {
232 SkASSERT(fLocalQuads.count() == fDeviceQuads.count());
233 for (int i = 0; i < this->quadCount(); ++i) {
234 const ColorAndAA& info = fDeviceQuads.metadata(i);
235 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
236 info.fColor, fLocalQuads[i], kEmptyDomain, info.fAAFlags);
237 }
Michael Ludwig69858532018-11-28 15:34:34 -0500238 }
239
240 // Configure the mesh for the vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500241 GrMesh* mesh = target->allocMeshes(1);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500242 if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, this->quadCount())) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500243 SkDebugf("Could not allocate indices\n");
244 return;
Michael Ludwig69858532018-11-28 15:34:34 -0500245 }
Brian Salomon12d22642019-01-29 14:38:50 -0500246 mesh->setVertexData(std::move(vbuffer), 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 {
255 TRACE_EVENT0("skia", TRACE_FUNC);
256 const auto* that = t->cast<FillRectOp>();
257
Michael Ludwig93aeba02018-12-21 09:50:31 -0500258 if ((fHelper.aaType() == GrAAType::kCoverage ||
259 that->fHelper.aaType() == GrAAType::kCoverage) &&
Michael Ludwigc96fc372019-01-08 15:46:15 -0500260 this->quadCount() + that->quadCount() > GrQuadPerEdgeAA::kNumAAQuadsInIndexBuffer) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500261 // This limit on batch size seems to help on Adreno devices
262 return CombineResult::kCannotCombine;
263 }
264
Michael Ludwigc96fc372019-01-08 15:46:15 -0500265 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
266 // ops together, so pass true as the last argument.
Michael Ludwig69858532018-11-28 15:34:34 -0500267 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
268 return CombineResult::kCannotCombine;
269 }
270
Michael Ludwigdcd48212019-01-08 15:28:57 -0500271 // If the paints were compatible, the trivial/solid-color state should be the same
272 SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
Michael Ludwig69858532018-11-28 15:34:34 -0500273
Michael Ludwigdcd48212019-01-08 15:28:57 -0500274 // If the processor sets are compatible, the two ops are always compatible; it just needs to
275 // adjust the state of the op to be the more general quad and aa types of the two ops and
276 // then concatenate the per-quad data.
Brian Salomon1d835422019-03-13 16:11:44 -0400277 fColorType = SkTMax(fColorType, that->fColorType);
Michael Ludwig69858532018-11-28 15:34:34 -0500278
279 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
280 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
281 // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
282 if (fHelper.aaType() == GrAAType::kNone && that->fHelper.aaType() == GrAAType::kCoverage) {
283 fHelper.setAAType(GrAAType::kCoverage);
284 }
285
Michael Ludwigc96fc372019-01-08 15:46:15 -0500286 fDeviceQuads.concat(that->fDeviceQuads);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500287 if (!fHelper.isTrivial()) {
288 fLocalQuads.concat(that->fLocalQuads);
289 }
Michael Ludwig69858532018-11-28 15:34:34 -0500290 return CombineResult::kMerged;
291 }
292
293 // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
294 // But since it's avoiding the op list management, it must update the op's bounds. This is only
295 // used with quad sets, which uses the same view matrix for each quad so this assumes that the
296 // device quad type of the new quad is the same as the op's.
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400297 void addQuad(const GrQuad& deviceQuad, const GrQuad& localQuad,
Michael Ludwig41f395d2019-05-23 13:59:45 -0400298 const SkPMColor4f& color, GrQuadAAFlags edgeAA, GrAAType aaType) {
Michael Ludwig69858532018-11-28 15:34:34 -0500299 // The new quad's aa type should be the same as the first quad's or none, except when the
300 // first quad's aa type was already downgraded to none, in which case the stored type must
301 // be lifted to back to the requested type.
302 if (aaType != fHelper.aaType()) {
303 if (aaType != GrAAType::kNone) {
304 // Original quad was downgraded to non-aa, lift back up to this quad's required type
305 SkASSERT(fHelper.aaType() == GrAAType::kNone);
306 fHelper.setAAType(aaType);
307 }
308 // else the new quad could have been downgraded but the other quads can't be, so don't
309 // reset the op's accumulated aa type.
310 }
311
Michael Ludwig69858532018-11-28 15:34:34 -0500312 // Update the bounds and add the quad to this op's storage
313 SkRect newBounds = this->bounds();
Michael Ludwig41f395d2019-05-23 13:59:45 -0400314 newBounds.joinPossiblyEmptyRect(deviceQuad.bounds());
Michael Ludwig69858532018-11-28 15:34:34 -0500315 this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
316 IsZeroArea::kNo);
Michael Ludwig41f395d2019-05-23 13:59:45 -0400317 fDeviceQuads.push_back(deviceQuad, { color, edgeAA });
Michael Ludwigdcd48212019-01-08 15:28:57 -0500318 if (!fHelper.isTrivial()) {
Michael Ludwig41f395d2019-05-23 13:59:45 -0400319 fLocalQuads.push_back(localQuad);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500320 }
Michael Ludwig69858532018-11-28 15:34:34 -0500321 }
322
Michael Ludwigc96fc372019-01-08 15:46:15 -0500323 int quadCount() const {
324 // Sanity check that the parallel arrays for quad properties all have the same size
Michael Ludwigdcd48212019-01-08 15:28:57 -0500325 SkASSERT(fDeviceQuads.count() == fLocalQuads.count() ||
326 (fLocalQuads.count() == 0 && fHelper.isTrivial()));
Michael Ludwigc96fc372019-01-08 15:46:15 -0500327 return fDeviceQuads.count();
328 }
329
330 struct ColorAndAA {
331 SkPMColor4f fColor;
332 GrQuadAAFlags fAAFlags;
333 };
Michael Ludwig69858532018-11-28 15:34:34 -0500334
335 Helper fHelper;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500336 GrTQuadList<ColorAndAA> fDeviceQuads;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500337 // No metadata attached to the local quads; this list is empty when local coords are not needed.
Michael Ludwigc96fc372019-01-08 15:46:15 -0500338 GrQuadList fLocalQuads;
Michael Ludwig69858532018-11-28 15:34:34 -0500339
Brian Salomon1d835422019-03-13 16:11:44 -0400340 ColorType fColorType;
Michael Ludwig69858532018-11-28 15:34:34 -0500341
Michael Ludwig69858532018-11-28 15:34:34 -0500342 typedef GrMeshDrawOp INHERITED;
343};
344
345} // anonymous namespace
346
347namespace GrFillRectOp {
348
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400349std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
350 GrPaint&& paint,
351 GrAAType aaType,
352 GrQuadAAFlags aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400353 const GrQuad& deviceQuad,
354 const GrQuad& localQuad,
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400355 const GrUserStencilSettings* stencil) {
Michael Ludwigd9f917b2019-05-24 12:57:55 -0400356 return FillRectOp::Make(context, std::move(paint), aaType, aaFlags, stencil,
357 deviceQuad, localQuad);
358}
359
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400360std::unique_ptr<GrDrawOp> MakeNonAARect(GrRecordingContext* context,
361 GrPaint&& paint,
362 const SkMatrix& view,
363 const SkRect& rect,
364 const GrUserStencilSettings* stencil) {
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400365 return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, GrQuadAAFlags::kNone,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400366 stencil, GrQuad::MakeFromRect(rect, view), GrQuad(rect));
Michael Ludwig009b92e2019-02-15 16:03:53 -0500367}
368
Robert Phillipsb97da532019-02-12 15:24:12 -0500369std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -0500370 GrPaint&& paint,
371 GrAAType aaType,
372 const SkMatrix& viewMatrix,
373 const GrRenderTargetContext::QuadSetEntry quads[],
374 int cnt,
375 const GrUserStencilSettings* stencilSettings) {
376 // First make a draw op for the first quad in the set
377 SkASSERT(cnt > 0);
Michael Ludwig69858532018-11-28 15:34:34 -0500378
379 paint.setColor4f(quads[0].fColor);
380 std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500381 quads[0].fAAFlags, stencilSettings,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400382 GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
383 GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix));
Michael Ludwig69858532018-11-28 15:34:34 -0500384 auto* fillRects = op->cast<FillRectOp>();
385
386 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
387 for (int i = 1; i < cnt; ++i) {
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400388 GrQuad deviceQuad = GrQuad::MakeFromRect(quads[i].fRect, viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500389
390 GrAAType resolvedAA;
391 GrQuadAAFlags resolvedEdgeFlags;
Michael Ludwig41f395d2019-05-23 13:59:45 -0400392 GrResolveAATypeForQuad(aaType, quads[i].fAAFlags, deviceQuad,
Michael Ludwig69858532018-11-28 15:34:34 -0500393 &resolvedAA, &resolvedEdgeFlags);
394
Michael Ludwige9c57d32019-02-13 13:39:39 -0500395 fillRects->addQuad(deviceQuad,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400396 GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
Michael Ludwig41f395d2019-05-23 13:59:45 -0400397 quads[i].fColor, resolvedEdgeFlags,resolvedAA);
Michael Ludwig69858532018-11-28 15:34:34 -0500398 }
399
400 return op;
401}
402
403} // namespace GrFillRectOp
404
405#if GR_TEST_UTILS
406
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500407#include "src/gpu/GrDrawOpTest.h"
408#include "src/gpu/SkGr.h"
Michael Ludwig69858532018-11-28 15:34:34 -0500409
410GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
411 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
412 SkRect rect = GrTest::TestRect(random);
413
414 GrAAType aaType = GrAAType::kNone;
415 if (random->nextBool()) {
416 aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
417 }
418 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
419 : GrGetRandomStencil(random, context);
420
421 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
422 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
423 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
424 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
425 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
426
427 if (random->nextBool()) {
428 if (random->nextBool()) {
429 if (random->nextBool()) {
430 // Local matrix with a set op
431 uint32_t extraQuadCt = random->nextRangeU(1, 4);
432 SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
433 quads.push_back(
434 {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
435 GrTest::TestMatrixInvertible(random), aaFlags});
436 for (uint32_t i = 0; i < extraQuadCt; ++i) {
437 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
438 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
439 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
440 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
441 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
442
443 quads.push_back(
444 {GrTest::TestRect(random),
445 SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
446 GrTest::TestMatrixInvertible(random), aaFlags});
447 }
448
449 return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
450 quads.begin(), quads.count(), stencil);
451 } else {
452 // Single local matrix
453 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400454 return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400455 GrQuad::MakeFromRect(rect, viewMatrix),
456 GrQuad::MakeFromRect(rect, localMatrix), stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500457 }
458 } else {
459 // Pass local rect directly
460 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400461 return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400462 GrQuad::MakeFromRect(rect, viewMatrix),
463 GrQuad(localRect), stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500464 }
465 } else {
466 // The simplest constructor
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400467 return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400468 GrQuad::MakeFromRect(rect, viewMatrix),
469 GrQuad(rect), stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500470 }
471}
472
473#endif