blob: 9cdf3f0cd1fcec8139e9f91503f17cdb6c4febb9 [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"
15#include "src/gpu/GrQuad.h"
16#include "src/gpu/SkGr.h"
17#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
18#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
19#include "src/gpu/glsl/GrGLSLVarying.h"
20#include "src/gpu/ops/GrMeshDrawOp.h"
21#include "src/gpu/ops/GrQuadPerEdgeAA.h"
22#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Michael Ludwig69858532018-11-28 15:34:34 -050023
24namespace {
25
26using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
27using ColorType = GrQuadPerEdgeAA::ColorType;
28
Michael Ludwigc96fc372019-01-08 15:46:15 -050029#ifdef SK_DEBUG
30static SkString dump_quad_info(int index, const GrPerspQuad& deviceQuad,
31 const GrPerspQuad& localQuad, const SkPMColor4f& color,
32 GrQuadAAFlags aaFlags) {
33 SkString str;
34 str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
35 " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
36 "(%.2f, %.2f, %.2f)],\n"
37 " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
38 "(%.2f, %.2f, %.2f)]\n",
39 index, color.fR, color.fG, color.fB, color.fA,
40 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
41 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
42 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
43 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
44 deviceQuad.x(0), deviceQuad.y(0), deviceQuad.w(0),
45 deviceQuad.x(1), deviceQuad.y(1), deviceQuad.w(1),
46 deviceQuad.x(2), deviceQuad.y(2), deviceQuad.w(2),
47 deviceQuad.x(3), deviceQuad.y(3), deviceQuad.w(3),
48 localQuad.x(0), localQuad.y(0), localQuad.w(0),
49 localQuad.x(1), localQuad.y(1), localQuad.w(1),
50 localQuad.x(2), localQuad.y(2), localQuad.w(2),
51 localQuad.x(3), localQuad.y(3), localQuad.w(3));
52 return str;
53}
54#endif
Michael Ludwig69858532018-11-28 15:34:34 -050055
Michael Ludwig69858532018-11-28 15:34:34 -050056class FillRectOp final : public GrMeshDrawOp {
57private:
58 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
59
60public:
Robert Phillipsb97da532019-02-12 15:24:12 -050061 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -050062 GrPaint&& paint,
63 GrAAType aaType,
64 GrQuadAAFlags edgeAA,
65 const GrUserStencilSettings* stencilSettings,
66 const GrPerspQuad& deviceQuad,
Michael Ludwig41f395d2019-05-23 13:59:45 -040067 const GrPerspQuad& localQuad) {
Michael Ludwig69858532018-11-28 15:34:34 -050068 // Clean up deviations between aaType and edgeAA
Michael Ludwig41f395d2019-05-23 13:59:45 -040069 GrResolveAATypeForQuad(aaType, edgeAA, deviceQuad, &aaType, &edgeAA);
Michael Ludwigdcd48212019-01-08 15:28:57 -050070 return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
Michael Ludwig41f395d2019-05-23 13:59:45 -040071 stencilSettings, deviceQuad, localQuad);
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 Ludwig41f395d2019-05-23 13:59:45 -040078 const GrPerspQuad& deviceQuad, const GrPerspQuad& localQuad)
Michael Ludwig69858532018-11-28 15:34:34 -050079 : INHERITED(ClassID())
Brian Osman8fa7ab42019-03-18 10:22:42 -040080 , fHelper(args, aaType, stencil) {
Michael Ludwig69858532018-11-28 15:34:34 -050081 // The color stored with the quad is the clear color if a scissor-clear is decided upon
82 // when executing the op.
Michael Ludwig41f395d2019-05-23 13:59:45 -040083 fDeviceQuads.push_back(deviceQuad, { paintColor, edgeFlags });
Michael Ludwigdcd48212019-01-08 15:28:57 -050084
85 if (!fHelper.isTrivial()) {
86 // Conservatively keep track of the local coordinates; it may be that the paint doesn't
87 // need them after analysis is finished. If the paint is known to be solid up front they
88 // can be skipped entirely.
Michael Ludwig41f395d2019-05-23 13:59:45 -040089 fLocalQuads.push_back(localQuad);
Michael Ludwigdcd48212019-01-08 15:28:57 -050090 }
Michael Ludwig41f395d2019-05-23 13:59:45 -040091 this->setBounds(deviceQuad.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
92 IsZeroArea::kNo);
Michael Ludwig69858532018-11-28 15:34:34 -050093 }
94
95 const char* name() const override { return "FillRectOp"; }
96
Chris Dalton1706cbf2019-05-21 19:35:29 -060097 void visitProxies(const VisitProxyFunc& func) const override {
Michael Ludwig69858532018-11-28 15:34:34 -050098 return fHelper.visitProxies(func);
99 }
100
101#ifdef SK_DEBUG
102 SkString dumpInfo() const override {
103 SkString str;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500104 str.appendf("# draws: %u\n", this->quadCount());
Michael Ludwig69858532018-11-28 15:34:34 -0500105 str.appendf("Device quad type: %u, local quad type: %u\n",
Michael Ludwigc96fc372019-01-08 15:46:15 -0500106 (uint32_t) fDeviceQuads.quadType(), (uint32_t) fLocalQuads.quadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500107 str += fHelper.dumpInfo();
Michael Ludwigc96fc372019-01-08 15:46:15 -0500108 GrPerspQuad device, local;
109 for (int i = 0; i < this->quadCount(); i++) {
110 device = fDeviceQuads[i];
111 const ColorAndAA& info = fDeviceQuads.metadata(i);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500112 if (!fHelper.isTrivial()) {
113 local = fLocalQuads[i];
114 }
Michael Ludwigc96fc372019-01-08 15:46:15 -0500115 str += dump_quad_info(i, device, local, info.fColor, info.fAAFlags);
Michael Ludwig69858532018-11-28 15:34:34 -0500116 }
117 str += INHERITED::dumpInfo();
118 return str;
119 }
120#endif
121
Brian Osman5ced0bf2019-03-15 10:15:29 -0400122 GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
123 GrFSAAType fsaaType, GrClampType clampType) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500124 // Initialize aggregate color analysis with the first quad's color (which always exists)
Michael Ludwigc96fc372019-01-08 15:46:15 -0500125 SkASSERT(this->quadCount() > 0);
126 GrProcessorAnalysisColor quadColors(fDeviceQuads.metadata(0).fColor);
Michael Ludwig69858532018-11-28 15:34:34 -0500127 // Then combine the colors of any additional quads (e.g. from MakeSet)
Michael Ludwigc96fc372019-01-08 15:46:15 -0500128 for (int i = 1; i < this->quadCount(); ++i) {
129 quadColors = GrProcessorAnalysisColor::Combine(quadColors,
130 fDeviceQuads.metadata(i).fColor);
Michael Ludwigca91e1f2018-12-10 10:44:44 -0500131 if (quadColors.isUnknown()) {
132 // No point in accumulating additional starting colors, combining cannot make it
133 // less unknown.
134 break;
135 }
Michael Ludwig69858532018-11-28 15:34:34 -0500136 }
Michael Ludwig72ab3462018-12-10 12:43:36 -0500137
138 // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
139 // then the coverage is always 1.0, so specify kNone for more optimal blending.
140 GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
141 GrProcessorAnalysisCoverage::kSingleChannel :
142 GrProcessorAnalysisCoverage::kNone;
Brian Osman5ced0bf2019-03-15 10:15:29 -0400143 auto result = fHelper.finalizeProcessors(
144 caps, clip, fsaaType, clampType, coverage, &quadColors);
Michael Ludwig69858532018-11-28 15:34:34 -0500145 // If there is a constant color after analysis, that means all of the quads should be set
146 // to the same color (even if they started out with different colors).
147 SkPMColor4f colorOverride;
148 if (quadColors.isConstant(&colorOverride)) {
Brian Osman8fa7ab42019-03-18 10:22:42 -0400149 fColorType = GrQuadPerEdgeAA::MinColorType(colorOverride, clampType, caps);
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 }
Brian Osman8fa7ab42019-03-18 10:22:42 -0400153 } else {
154 // Otherwise compute the color type needed as the max over all quads.
155 fColorType = ColorType::kNone;
156 for (int i = 0; i < this->quadCount(); ++i) {
157 SkPMColor4f* color = &fDeviceQuads.metadata(i).fColor;
158 fColorType = SkTMax(fColorType,
159 GrQuadPerEdgeAA::MinColorType(*color, clampType, caps));
160 }
Michael Ludwig69858532018-11-28 15:34:34 -0500161 }
Brian Salomon41f9c3c2019-03-25 11:06:12 -0400162 // Most SkShaders' FPs multiply their calculated color by the paint color or alpha. We want
163 // to use ColorType::kNone to optimize out that multiply. However, if there are no color
164 // FPs then were really writing a special shader for white rectangles and not saving any
165 // multiples. So in that case use bytes to avoid the extra shader (and possibly work around
166 // an ANGLE issue: crbug.com/942565).
167 if (fColorType == ColorType::kNone && !result.hasColorFragmentProcessor()) {
168 fColorType = ColorType::kByte;
169 }
Michael Ludwig69858532018-11-28 15:34:34 -0500170
171 return result;
172 }
173
174 FixedFunctionFlags fixedFunctionFlags() const override {
175 // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
176 // the helper's fixed function flags are appropriate.
177 return fHelper.fixedFunctionFlags();
178 }
179
180 DEFINE_OP_CLASS_ID
181
182private:
183 // For GrFillRectOp::MakeSet's use of addQuad
Robert Phillipsb97da532019-02-12 15:24:12 -0500184 friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(
185 GrRecordingContext*,
186 GrPaint&&,
187 GrAAType, const SkMatrix& viewMatrix,
Michael Ludwig69858532018-11-28 15:34:34 -0500188 const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
Robert Phillipsb97da532019-02-12 15:24:12 -0500189 const GrUserStencilSettings*);
Michael Ludwig69858532018-11-28 15:34:34 -0500190
Michael Ludwigc96fc372019-01-08 15:46:15 -0500191 void onPrepareDraws(Target* target) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500192 TRACE_EVENT0("skia", TRACE_FUNC);
193
194 using Domain = GrQuadPerEdgeAA::Domain;
195 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
196
Brian Salomon1d835422019-03-13 16:11:44 -0400197 VertexSpec vertexSpec(fDeviceQuads.quadType(), fColorType, fLocalQuads.quadType(),
198 fHelper.usesLocalCoords(), Domain::kNo, fHelper.aaType(),
Brian Osman605c6d52019-03-15 12:10:35 -0400199 fHelper.compatibleWithCoverageAsAlpha());
Michael Ludwigdcd48212019-01-08 15:28:57 -0500200 // Make sure that if the op thought it was a solid color, the vertex spec does not use
201 // local coords.
202 SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
Michael Ludwig69858532018-11-28 15:34:34 -0500203
Michael Ludwig467994d2018-12-03 14:58:31 +0000204 sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
Michael Ludwig69858532018-11-28 15:34:34 -0500205 size_t vertexSize = gp->vertexStride();
206
Brian Salomon12d22642019-01-29 14:38:50 -0500207 sk_sp<const GrBuffer> vbuffer;
Michael Ludwig69858532018-11-28 15:34:34 -0500208 int vertexOffsetInBuffer = 0;
209
210 // Fill the allocated vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500211 void* vdata = target->makeVertexSpace(
Michael Ludwigc96fc372019-01-08 15:46:15 -0500212 vertexSize, this->quadCount() * vertexSpec.verticesPerQuad(),
Michael Ludwig93aeba02018-12-21 09:50:31 -0500213 &vbuffer, &vertexOffsetInBuffer);
Michael Ludwig69858532018-11-28 15:34:34 -0500214 if (!vdata) {
215 SkDebugf("Could not allocate vertices\n");
216 return;
217 }
218
219 // vertices pointer advances through vdata based on Tessellate's return value
220 void* vertices = vdata;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500221 if (fHelper.isTrivial()) {
222 SkASSERT(fLocalQuads.count() == 0); // No local coords, so send an ignored dummy quad
Michael Ludwige9c57d32019-02-13 13:39:39 -0500223 static const GrPerspQuad kIgnoredLocal(SkRect::MakeEmpty());
224
Michael Ludwigdcd48212019-01-08 15:28:57 -0500225 for (int i = 0; i < this->quadCount(); ++i) {
226 const ColorAndAA& info = fDeviceQuads.metadata(i);
227 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
228 info.fColor, kIgnoredLocal, kEmptyDomain, info.fAAFlags);
229 }
230 } else {
231 SkASSERT(fLocalQuads.count() == fDeviceQuads.count());
232 for (int i = 0; i < this->quadCount(); ++i) {
233 const ColorAndAA& info = fDeviceQuads.metadata(i);
234 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
235 info.fColor, fLocalQuads[i], kEmptyDomain, info.fAAFlags);
236 }
Michael Ludwig69858532018-11-28 15:34:34 -0500237 }
238
239 // Configure the mesh for the vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500240 GrMesh* mesh = target->allocMeshes(1);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500241 if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, this->quadCount())) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500242 SkDebugf("Could not allocate indices\n");
243 return;
Michael Ludwig69858532018-11-28 15:34:34 -0500244 }
Brian Salomon12d22642019-01-29 14:38:50 -0500245 mesh->setVertexData(std::move(vbuffer), vertexOffsetInBuffer);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700246 target->recordDraw(std::move(gp), mesh);
247 }
Michael Ludwig69858532018-11-28 15:34:34 -0500248
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700249 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
250 fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
251 }
Michael Ludwig69858532018-11-28 15:34:34 -0500252
253 CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
254 TRACE_EVENT0("skia", TRACE_FUNC);
255 const auto* that = t->cast<FillRectOp>();
256
Michael Ludwig93aeba02018-12-21 09:50:31 -0500257 if ((fHelper.aaType() == GrAAType::kCoverage ||
258 that->fHelper.aaType() == GrAAType::kCoverage) &&
Michael Ludwigc96fc372019-01-08 15:46:15 -0500259 this->quadCount() + that->quadCount() > GrQuadPerEdgeAA::kNumAAQuadsInIndexBuffer) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500260 // This limit on batch size seems to help on Adreno devices
261 return CombineResult::kCannotCombine;
262 }
263
Michael Ludwigc96fc372019-01-08 15:46:15 -0500264 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
265 // ops together, so pass true as the last argument.
Michael Ludwig69858532018-11-28 15:34:34 -0500266 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
267 return CombineResult::kCannotCombine;
268 }
269
Michael Ludwigdcd48212019-01-08 15:28:57 -0500270 // If the paints were compatible, the trivial/solid-color state should be the same
271 SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
Michael Ludwig69858532018-11-28 15:34:34 -0500272
Michael Ludwigdcd48212019-01-08 15:28:57 -0500273 // If the processor sets are compatible, the two ops are always compatible; it just needs to
274 // adjust the state of the op to be the more general quad and aa types of the two ops and
275 // then concatenate the per-quad data.
Brian Salomon1d835422019-03-13 16:11:44 -0400276 fColorType = SkTMax(fColorType, that->fColorType);
Michael Ludwig69858532018-11-28 15:34:34 -0500277
278 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
279 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
280 // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
281 if (fHelper.aaType() == GrAAType::kNone && that->fHelper.aaType() == GrAAType::kCoverage) {
282 fHelper.setAAType(GrAAType::kCoverage);
283 }
284
Michael Ludwigc96fc372019-01-08 15:46:15 -0500285 fDeviceQuads.concat(that->fDeviceQuads);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500286 if (!fHelper.isTrivial()) {
287 fLocalQuads.concat(that->fLocalQuads);
288 }
Michael Ludwig69858532018-11-28 15:34:34 -0500289 return CombineResult::kMerged;
290 }
291
292 // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
293 // But since it's avoiding the op list management, it must update the op's bounds. This is only
294 // used with quad sets, which uses the same view matrix for each quad so this assumes that the
295 // device quad type of the new quad is the same as the op's.
Michael Ludwigc96fc372019-01-08 15:46:15 -0500296 void addQuad(const GrPerspQuad& deviceQuad, const GrPerspQuad& localQuad,
Michael Ludwig41f395d2019-05-23 13:59:45 -0400297 const SkPMColor4f& color, GrQuadAAFlags edgeAA, GrAAType aaType) {
Michael Ludwig69858532018-11-28 15:34:34 -0500298 // The new quad's aa type should be the same as the first quad's or none, except when the
299 // first quad's aa type was already downgraded to none, in which case the stored type must
300 // be lifted to back to the requested type.
301 if (aaType != fHelper.aaType()) {
302 if (aaType != GrAAType::kNone) {
303 // Original quad was downgraded to non-aa, lift back up to this quad's required type
304 SkASSERT(fHelper.aaType() == GrAAType::kNone);
305 fHelper.setAAType(aaType);
306 }
307 // else the new quad could have been downgraded but the other quads can't be, so don't
308 // reset the op's accumulated aa type.
309 }
310
Michael Ludwig69858532018-11-28 15:34:34 -0500311 // Update the bounds and add the quad to this op's storage
312 SkRect newBounds = this->bounds();
Michael Ludwig41f395d2019-05-23 13:59:45 -0400313 newBounds.joinPossiblyEmptyRect(deviceQuad.bounds());
Michael Ludwig69858532018-11-28 15:34:34 -0500314 this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
315 IsZeroArea::kNo);
Michael Ludwig41f395d2019-05-23 13:59:45 -0400316 fDeviceQuads.push_back(deviceQuad, { color, edgeAA });
Michael Ludwigdcd48212019-01-08 15:28:57 -0500317 if (!fHelper.isTrivial()) {
Michael Ludwig41f395d2019-05-23 13:59:45 -0400318 fLocalQuads.push_back(localQuad);
Michael Ludwigdcd48212019-01-08 15:28:57 -0500319 }
Michael Ludwig69858532018-11-28 15:34:34 -0500320 }
321
Michael Ludwigc96fc372019-01-08 15:46:15 -0500322 int quadCount() const {
323 // Sanity check that the parallel arrays for quad properties all have the same size
Michael Ludwigdcd48212019-01-08 15:28:57 -0500324 SkASSERT(fDeviceQuads.count() == fLocalQuads.count() ||
325 (fLocalQuads.count() == 0 && fHelper.isTrivial()));
Michael Ludwigc96fc372019-01-08 15:46:15 -0500326 return fDeviceQuads.count();
327 }
328
329 struct ColorAndAA {
330 SkPMColor4f fColor;
331 GrQuadAAFlags fAAFlags;
332 };
Michael Ludwig69858532018-11-28 15:34:34 -0500333
334 Helper fHelper;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500335 GrTQuadList<ColorAndAA> fDeviceQuads;
Michael Ludwigdcd48212019-01-08 15:28:57 -0500336 // No metadata attached to the local quads; this list is empty when local coords are not needed.
Michael Ludwigc96fc372019-01-08 15:46:15 -0500337 GrQuadList fLocalQuads;
Michael Ludwig69858532018-11-28 15:34:34 -0500338
Brian Salomon1d835422019-03-13 16:11:44 -0400339 ColorType fColorType;
Michael Ludwig69858532018-11-28 15:34:34 -0500340
Michael Ludwig69858532018-11-28 15:34:34 -0500341 typedef GrMeshDrawOp INHERITED;
342};
343
344} // anonymous namespace
345
346namespace GrFillRectOp {
347
Michael Ludwigd9f917b2019-05-24 12:57:55 -0400348std::unique_ptr<GrDrawOp> MakeGeneric(GrRecordingContext* context,
349 GrPaint&& paint,
350 GrAAType aaType,
351 GrQuadAAFlags aaFlags,
352 const GrPerspQuad& deviceQuad,
353 const GrPerspQuad& localQuad,
354 const GrUserStencilSettings* stencil) {
355 return FillRectOp::Make(context, std::move(paint), aaType, aaFlags, stencil,
356 deviceQuad, localQuad);
357}
358
Robert Phillipsb97da532019-02-12 15:24:12 -0500359std::unique_ptr<GrDrawOp> MakePerEdge(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500360 GrPaint&& paint,
361 GrAAType aaType,
362 GrQuadAAFlags edgeAA,
363 const SkMatrix& viewMatrix,
364 const SkRect& rect,
365 const GrUserStencilSettings* stencilSettings) {
Michael Ludwigd9f917b2019-05-24 12:57:55 -0400366 return MakeGeneric(context, std::move(paint), aaType, edgeAA,
367 GrPerspQuad::MakeFromRect(rect, viewMatrix),
368 GrPerspQuad(rect), stencilSettings);
Michael Ludwig69858532018-11-28 15:34:34 -0500369}
370
Robert Phillipsb97da532019-02-12 15:24:12 -0500371std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500372 GrPaint&& paint,
373 GrAAType aaType,
374 GrQuadAAFlags edgeAA,
375 const SkMatrix& viewMatrix,
376 const SkMatrix& localMatrix,
377 const SkRect& rect,
378 const GrUserStencilSettings* stencilSettings) {
Michael Ludwigd9f917b2019-05-24 12:57:55 -0400379 return MakeGeneric(context, std::move(paint), aaType, edgeAA,
380 GrPerspQuad::MakeFromRect(rect, viewMatrix),
381 GrPerspQuad::MakeFromRect(rect, localMatrix), stencilSettings);
Michael Ludwig69858532018-11-28 15:34:34 -0500382}
383
Robert Phillipsb97da532019-02-12 15:24:12 -0500384std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500385 GrPaint&& paint,
386 GrAAType aaType,
387 GrQuadAAFlags edgeAA,
388 const SkMatrix& viewMatrix,
389 const SkRect& rect,
390 const SkRect& localRect,
391 const GrUserStencilSettings* stencilSettings) {
Michael Ludwigd9f917b2019-05-24 12:57:55 -0400392 return MakeGeneric(context, std::move(paint), aaType, edgeAA,
393 GrPerspQuad::MakeFromRect(rect, viewMatrix),
394 GrPerspQuad(localRect), stencilSettings);
Michael Ludwig69858532018-11-28 15:34:34 -0500395}
396
Michael Ludwig009b92e2019-02-15 16:03:53 -0500397std::unique_ptr<GrDrawOp> MakePerEdgeQuad(GrRecordingContext* context,
398 GrPaint&& paint,
399 GrAAType aaType,
400 GrQuadAAFlags edgeAA,
401 const SkMatrix& viewMatrix,
402 const SkPoint quad[4],
403 const SkPoint localQuad[4],
404 const GrUserStencilSettings* stencilSettings) {
Michael Ludwigd9f917b2019-05-24 12:57:55 -0400405 const SkPoint* localPoints = localQuad ? localQuad : quad;
406 return MakeGeneric(context, std::move(paint), aaType, edgeAA,
407 GrPerspQuad::MakeFromSkQuad(quad, viewMatrix),
408 GrPerspQuad::MakeFromSkQuad(localPoints, SkMatrix::I()), stencilSettings);
Michael Ludwig009b92e2019-02-15 16:03:53 -0500409}
410
Robert Phillipsb97da532019-02-12 15:24:12 -0500411std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -0500412 GrPaint&& paint,
413 GrAAType aaType,
414 const SkMatrix& viewMatrix,
415 const GrRenderTargetContext::QuadSetEntry quads[],
416 int cnt,
417 const GrUserStencilSettings* stencilSettings) {
418 // First make a draw op for the first quad in the set
419 SkASSERT(cnt > 0);
Michael Ludwig69858532018-11-28 15:34:34 -0500420
421 paint.setColor4f(quads[0].fColor);
422 std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500423 quads[0].fAAFlags, stencilSettings,
Michael Ludwig41f395d2019-05-23 13:59:45 -0400424 GrPerspQuad::MakeFromRect(quads[0].fRect, viewMatrix),
425 GrPerspQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix));
Michael Ludwig69858532018-11-28 15:34:34 -0500426 auto* fillRects = op->cast<FillRectOp>();
427
428 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
429 for (int i = 1; i < cnt; ++i) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500430 GrPerspQuad deviceQuad = GrPerspQuad::MakeFromRect(quads[i].fRect, viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500431
432 GrAAType resolvedAA;
433 GrQuadAAFlags resolvedEdgeFlags;
Michael Ludwig41f395d2019-05-23 13:59:45 -0400434 GrResolveAATypeForQuad(aaType, quads[i].fAAFlags, deviceQuad,
Michael Ludwig69858532018-11-28 15:34:34 -0500435 &resolvedAA, &resolvedEdgeFlags);
436
Michael Ludwige9c57d32019-02-13 13:39:39 -0500437 fillRects->addQuad(deviceQuad,
438 GrPerspQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
Michael Ludwig41f395d2019-05-23 13:59:45 -0400439 quads[i].fColor, resolvedEdgeFlags,resolvedAA);
Michael Ludwig69858532018-11-28 15:34:34 -0500440 }
441
442 return op;
443}
444
Robert Phillipsb97da532019-02-12 15:24:12 -0500445std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500446 GrPaint&& paint,
447 GrAAType aaType,
448 const SkMatrix& viewMatrix,
449 const SkRect& rect,
450 const GrUserStencilSettings* stencil) {
451 return MakePerEdge(context, std::move(paint), aaType,
452 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
453 viewMatrix, rect, stencil);
454}
455
Robert Phillipsb97da532019-02-12 15:24:12 -0500456std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500457 GrPaint&& paint,
458 GrAAType aaType,
459 const SkMatrix& viewMatrix,
460 const SkMatrix& localMatrix,
461 const SkRect& rect,
462 const GrUserStencilSettings* stencil) {
463 return MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
464 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
465 viewMatrix, localMatrix, rect, stencil);
466}
467
Robert Phillipsb97da532019-02-12 15:24:12 -0500468std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrRecordingContext* context,
Michael Ludwig72ab3462018-12-10 12:43:36 -0500469 GrPaint&& paint,
470 GrAAType aaType,
471 const SkMatrix& viewMatrix,
472 const SkRect& rect,
473 const SkRect& localRect,
474 const GrUserStencilSettings* stencil) {
475 return MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
476 aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
477 viewMatrix, rect, localRect, stencil);
478}
479
Michael Ludwig69858532018-11-28 15:34:34 -0500480} // namespace GrFillRectOp
481
482#if GR_TEST_UTILS
483
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500484#include "src/gpu/GrDrawOpTest.h"
485#include "src/gpu/SkGr.h"
Michael Ludwig69858532018-11-28 15:34:34 -0500486
487GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
488 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
489 SkRect rect = GrTest::TestRect(random);
490
491 GrAAType aaType = GrAAType::kNone;
492 if (random->nextBool()) {
493 aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
494 }
495 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
496 : GrGetRandomStencil(random, context);
497
498 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
499 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
500 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
501 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
502 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
503
504 if (random->nextBool()) {
505 if (random->nextBool()) {
506 if (random->nextBool()) {
507 // Local matrix with a set op
508 uint32_t extraQuadCt = random->nextRangeU(1, 4);
509 SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
510 quads.push_back(
511 {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
512 GrTest::TestMatrixInvertible(random), aaFlags});
513 for (uint32_t i = 0; i < extraQuadCt; ++i) {
514 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
515 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
516 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
517 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
518 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
519
520 quads.push_back(
521 {GrTest::TestRect(random),
522 SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
523 GrTest::TestMatrixInvertible(random), aaFlags});
524 }
525
526 return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
527 quads.begin(), quads.count(), stencil);
528 } else {
529 // Single local matrix
530 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500531 return GrFillRectOp::MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
532 aaFlags, viewMatrix, localMatrix,
533 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500534 }
535 } else {
536 // Pass local rect directly
537 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500538 return GrFillRectOp::MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
539 aaFlags, viewMatrix, rect, localRect,
540 stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500541 }
542 } else {
543 // The simplest constructor
Michael Ludwig72ab3462018-12-10 12:43:36 -0500544 return GrFillRectOp::MakePerEdge(context, std::move(paint), aaType, aaFlags, viewMatrix,
545 rect, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500546 }
547}
548
549#endif