blob: 4c6bfdaa49fe46cfac0f5255cfa57df8c7574dd7 [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 Ludwig704d5402019-11-25 09:43:37 -050032static 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) {
Michael Ludwig704d5402019-11-25 09:43:37 -050035 GrQuad safeLocal = localQuad ? *localQuad : GrQuad();
Michael Ludwigc96fc372019-01-08 15:46:15 -050036 SkString str;
37 str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
38 " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
39 "(%.2f, %.2f, %.2f)],\n"
40 " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
41 "(%.2f, %.2f, %.2f)]\n",
42 index, color.fR, color.fG, color.fB, color.fA,
43 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
44 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
45 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
46 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
Michael Ludwig704d5402019-11-25 09:43:37 -050047 deviceQuad->x(0), deviceQuad->y(0), deviceQuad->w(0),
48 deviceQuad->x(1), deviceQuad->y(1), deviceQuad->w(1),
49 deviceQuad->x(2), deviceQuad->y(2), deviceQuad->w(2),
50 deviceQuad->x(3), deviceQuad->y(3), deviceQuad->w(3),
51 safeLocal.x(0), safeLocal.y(0), safeLocal.w(0),
52 safeLocal.x(1), safeLocal.y(1), safeLocal.w(1),
53 safeLocal.x(2), safeLocal.y(2), safeLocal.w(2),
54 safeLocal.x(3), safeLocal.y(3), safeLocal.w(3));
Michael Ludwigc96fc372019-01-08 15:46:15 -050055 return str;
56}
57#endif
Michael Ludwig69858532018-11-28 15:34:34 -050058
Michael Ludwig69858532018-11-28 15:34:34 -050059class FillRectOp final : public GrMeshDrawOp {
60private:
61 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
62
63public:
Robert Phillipsb97da532019-02-12 15:24:12 -050064 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -050065 GrPaint&& paint,
66 GrAAType aaType,
67 GrQuadAAFlags edgeAA,
68 const GrUserStencilSettings* stencilSettings,
Michael Ludwigde4c58c2019-06-04 09:12:59 -040069 const GrQuad& deviceQuad,
70 const GrQuad& localQuad) {
Michael Ludwig69858532018-11-28 15:34:34 -050071 // Clean up deviations between aaType and edgeAA
Michael Ludwig0f809022019-06-04 09:14:37 -040072 GrQuadUtils::ResolveAAType(aaType, edgeAA, deviceQuad, &aaType, &edgeAA);
Michael Ludwigdcd48212019-01-08 15:28:57 -050073 return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
Michael Ludwig41f395d2019-05-23 13:59:45 -040074 stencilSettings, deviceQuad, localQuad);
Michael Ludwig69858532018-11-28 15:34:34 -050075 }
76
Michael Ludwigdcd48212019-01-08 15:28:57 -050077 // aaType is passed to Helper in the initializer list, so incongruities between aaType and
78 // edgeFlags must be resolved prior to calling this constructor.
79 FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
80 GrQuadAAFlags edgeFlags, const GrUserStencilSettings* stencil,
Michael Ludwigde4c58c2019-06-04 09:12:59 -040081 const GrQuad& deviceQuad, const GrQuad& localQuad)
Michael Ludwig69858532018-11-28 15:34:34 -050082 : INHERITED(ClassID())
Michael Ludwig425eb452019-06-27 10:13:27 -040083 , fHelper(args, aaType, stencil)
84 , fQuads(1, !fHelper.isTrivial()) {
85 // Conservatively keep track of the local coordinates; it may be that the paint doesn't
86 // need them after analysis is finished. If the paint is known to be solid up front they
87 // can be skipped entirely.
88 fQuads.append(deviceQuad, { paintColor, edgeFlags },
89 fHelper.isTrivial() ? nullptr : &localQuad);
Michael Ludwig41f395d2019-05-23 13:59:45 -040090 this->setBounds(deviceQuad.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
Greg Daniel5faf4742019-10-01 15:14:44 -040091 IsHairline::kNo);
Michael Ludwig69858532018-11-28 15:34:34 -050092 }
93
94 const char* name() const override { return "FillRectOp"; }
95
Chris Dalton1706cbf2019-05-21 19:35:29 -060096 void visitProxies(const VisitProxyFunc& func) const override {
Michael Ludwig69858532018-11-28 15:34:34 -050097 return fHelper.visitProxies(func);
98 }
99
100#ifdef SK_DEBUG
101 SkString dumpInfo() const override {
102 SkString str;
Michael Ludwig425eb452019-06-27 10:13:27 -0400103 str.appendf("# draws: %u\n", fQuads.count());
Michael Ludwig69858532018-11-28 15:34:34 -0500104 str.appendf("Device quad type: %u, local quad type: %u\n",
Michael Ludwig425eb452019-06-27 10:13:27 -0400105 (uint32_t) fQuads.deviceQuadType(), (uint32_t) fQuads.localQuadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500106 str += fHelper.dumpInfo();
Michael Ludwig425eb452019-06-27 10:13:27 -0400107 int i = 0;
108 auto iter = fQuads.iterator();
109 while(iter.next()) {
110 const ColorAndAA& info = iter.metadata();
111 str += dump_quad_info(i, iter.deviceQuad(), iter.localQuad(),
112 info.fColor, info.fAAFlags);
113 i++;
Michael Ludwig69858532018-11-28 15:34:34 -0500114 }
115 str += INHERITED::dumpInfo();
116 return str;
117 }
118#endif
119
Chris Dalton6ce447a2019-06-23 18:07:38 -0600120 GrProcessorSet::Analysis finalize(
121 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
122 GrClampType clampType) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500123 // Initialize aggregate color analysis with the first quad's color (which always exists)
Michael Ludwig425eb452019-06-27 10:13:27 -0400124 auto iter = fQuads.metadata();
125 SkAssertResult(iter.next());
126 GrProcessorAnalysisColor quadColors(iter->fColor);
Michael Ludwig69858532018-11-28 15:34:34 -0500127 // Then combine the colors of any additional quads (e.g. from MakeSet)
Michael Ludwig425eb452019-06-27 10:13:27 -0400128 while(iter.next()) {
129 quadColors = GrProcessorAnalysisColor::Combine(quadColors, iter->fColor);
Michael Ludwigca91e1f2018-12-10 10:44:44 -0500130 if (quadColors.isUnknown()) {
131 // No point in accumulating additional starting colors, combining cannot make it
132 // less unknown.
133 break;
134 }
Michael Ludwig69858532018-11-28 15:34:34 -0500135 }
Michael Ludwig72ab3462018-12-10 12:43:36 -0500136
137 // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
138 // then the coverage is always 1.0, so specify kNone for more optimal blending.
139 GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
140 GrProcessorAnalysisCoverage::kSingleChannel :
141 GrProcessorAnalysisCoverage::kNone;
Brian Osman5ced0bf2019-03-15 10:15:29 -0400142 auto result = fHelper.finalizeProcessors(
Chris Dalton6ce447a2019-06-23 18:07:38 -0600143 caps, clip, hasMixedSampledCoverage, clampType, coverage, &quadColors);
Michael Ludwig69858532018-11-28 15:34:34 -0500144 // If there is a constant color after analysis, that means all of the quads should be set
145 // to the same color (even if they started out with different colors).
Michael Ludwig425eb452019-06-27 10:13:27 -0400146 iter = fQuads.metadata();
Michael Ludwig69858532018-11-28 15:34:34 -0500147 SkPMColor4f colorOverride;
148 if (quadColors.isConstant(&colorOverride)) {
Brian Osman2715bf52019-12-06 14:38:47 -0500149 fColorType = GrQuadPerEdgeAA::MinColorType(colorOverride);
Michael Ludwig425eb452019-06-27 10:13:27 -0400150 while(iter.next()) {
151 iter->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;
Michael Ludwig425eb452019-06-27 10:13:27 -0400156 while(iter.next()) {
Brian Osman2715bf52019-12-06 14:38:47 -0500157 fColorType = SkTMax(fColorType, GrQuadPerEdgeAA::MinColorType(iter->fColor));
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:
Robert Phillips438d9862019-11-14 12:46:05 -0500181 friend class ::GrFillRectOp; // for access to addQuad
182
183#if GR_TEST_UTILS
184 int numQuads() const final { return fQuads.count(); }
185#endif
Michael Ludwig69858532018-11-28 15:34:34 -0500186
Robert Phillips93209052019-12-03 15:42:35 -0500187 VertexSpec vertexSpec() const {
Robert Phillipsc554dcf2019-10-28 11:43:55 -0400188 auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(fHelper.aaType(),
189 fQuads.count());
190
Robert Phillips93209052019-12-03 15:42:35 -0500191 return VertexSpec(fQuads.deviceQuadType(), fColorType, fQuads.localQuadType(),
192 fHelper.usesLocalCoords(), GrQuadPerEdgeAA::Domain::kNo,
193 fHelper.aaType(),
194 fHelper.compatibleWithCoverageAsAlpha(), indexBufferOption);
195 }
196
197 void onPrePrepareDraws(GrRecordingContext* context,
198 const GrSurfaceProxyView*,
199 GrAppliedClip*,
200 const GrXferProcessor::DstProxyView&) override {
201 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
202
203 SkASSERT(!fPrePreparedVertices);
204
205 SkArenaAlloc* arena = context->priv().recordTimeAllocator();
206
207 const VertexSpec vertexSpec = this->vertexSpec();
208
209 const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
210 const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
211
212 fPrePreparedVertices = arena->makeArrayDefault<char>(totalVertexSizeInBytes);
213
214 this->tessellate(vertexSpec, fPrePreparedVertices);
215 }
216
217 void tessellate(const VertexSpec& vertexSpec, char* dst) const {
218 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
219
220 GrQuadPerEdgeAA::Tessellator tessellator(vertexSpec, dst);
221 auto iter = fQuads.iterator();
222 while (iter.next()) {
223 // All entries should have local coords, or no entries should have local coords,
224 // matching !helper.isTrivial() (which is more conservative than helper.usesLocalCoords)
225 SkASSERT(iter.isLocalValid() != fHelper.isTrivial());
226 auto info = iter.metadata();
227 tessellator.append(iter.deviceQuad(), iter.localQuad(),
228 info.fColor, kEmptyDomain, info.fAAFlags);
229 }
230 }
231
232 void onPrepareDraws(Target* target) override {
233 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
234
235 const VertexSpec vertexSpec = this->vertexSpec();
236
Michael Ludwigdcd48212019-01-08 15:28:57 -0500237 // Make sure that if the op thought it was a solid color, the vertex spec does not use
238 // local coords.
239 SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
Michael Ludwig69858532018-11-28 15:34:34 -0500240
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500241 GrGeometryProcessor* gp = GrQuadPerEdgeAA::MakeProcessor(target->allocator(), vertexSpec);
Robert Phillips93209052019-12-03 15:42:35 -0500242 SkASSERT(gp->vertexStride() == vertexSpec.vertexSize());
Michael Ludwig69858532018-11-28 15:34:34 -0500243
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400244 sk_sp<const GrBuffer> vertexBuffer;
Michael Ludwig69858532018-11-28 15:34:34 -0500245 int vertexOffsetInBuffer = 0;
246
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400247 const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
248
Michael Ludwig69858532018-11-28 15:34:34 -0500249 // Fill the allocated vertex data
Robert Phillips93209052019-12-03 15:42:35 -0500250 void* vdata = target->makeVertexSpace(vertexSpec.vertexSize(), totalNumVertices,
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400251 &vertexBuffer, &vertexOffsetInBuffer);
Michael Ludwig69858532018-11-28 15:34:34 -0500252 if (!vdata) {
253 SkDebugf("Could not allocate vertices\n");
254 return;
255 }
256
Robert Phillips93209052019-12-03 15:42:35 -0500257 if (fPrePreparedVertices) {
258 const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
259
260 memcpy(vdata, fPrePreparedVertices, totalVertexSizeInBytes);
261 } else {
262 this->tessellate(vertexSpec, (char*) vdata);
Michael Ludwig69858532018-11-28 15:34:34 -0500263 }
264
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400265 sk_sp<const GrBuffer> indexBuffer;
266 if (vertexSpec.needsIndexBuffer()) {
267 indexBuffer = GrQuadPerEdgeAA::GetIndexBuffer(target, vertexSpec.indexBufferOption());
268 if (!indexBuffer) {
269 SkDebugf("Could not allocate indices\n");
270 return;
271 }
272 }
273
Michael Ludwig69858532018-11-28 15:34:34 -0500274 // Configure the mesh for the vertex data
Michael Ludwig93aeba02018-12-21 09:50:31 -0500275 GrMesh* mesh = target->allocMeshes(1);
Robert Phillips2f05a482019-11-25 09:54:43 -0500276 GrQuadPerEdgeAA::ConfigureMesh(target->caps(), mesh, vertexSpec, 0, fQuads.count(),
277 totalNumVertices, std::move(vertexBuffer),
278 std::move(indexBuffer), vertexOffsetInBuffer);
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500279 target->recordDraw(gp, mesh, 1, vertexSpec.primitiveType());
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700280 }
Michael Ludwig69858532018-11-28 15:34:34 -0500281
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700282 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillips3968fcb2019-12-05 16:40:31 -0500283 auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState,
284 fHelper.detachProcessorSet(),
285 fHelper.pipelineFlags(),
286 fHelper.stencilSettings());
287
288 flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700289 }
Michael Ludwig69858532018-11-28 15:34:34 -0500290
Michael Ludwig28b0c5d2019-12-19 14:51:00 -0500291 CombineResult onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*,
292 const GrCaps& caps) override {
Brian Salomon5f394272019-07-02 14:07:49 -0400293 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Michael Ludwig69858532018-11-28 15:34:34 -0500294 const auto* that = t->cast<FillRectOp>();
295
Robert Phillipsb69001f2019-10-29 12:16:35 -0400296 bool upgradeToCoverageAAOnMerge = false;
297 if (fHelper.aaType() != that->fHelper.aaType()) {
Robert Phillipsbbd459d2019-10-29 14:40:03 -0400298 if (!CanUpgradeAAOnMerge(fHelper.aaType(), that->fHelper.aaType())) {
Robert Phillipsb69001f2019-10-29 12:16:35 -0400299 return CombineResult::kCannotCombine;
300 }
301 upgradeToCoverageAAOnMerge = true;
302 }
303
Robert Phillipsbbd459d2019-10-29 14:40:03 -0400304 if (CombinedQuadCountWillOverflow(fHelper.aaType(), upgradeToCoverageAAOnMerge,
305 fQuads.count() + that->fQuads.count())) {
306 return CombineResult::kCannotCombine;
Michael Ludwig93aeba02018-12-21 09:50:31 -0500307 }
308
Michael Ludwigc96fc372019-01-08 15:46:15 -0500309 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
310 // ops together, so pass true as the last argument.
Michael Ludwig69858532018-11-28 15:34:34 -0500311 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
312 return CombineResult::kCannotCombine;
313 }
314
Michael Ludwigdcd48212019-01-08 15:28:57 -0500315 // If the paints were compatible, the trivial/solid-color state should be the same
316 SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
Michael Ludwig69858532018-11-28 15:34:34 -0500317
Michael Ludwigdcd48212019-01-08 15:28:57 -0500318 // If the processor sets are compatible, the two ops are always compatible; it just needs to
319 // adjust the state of the op to be the more general quad and aa types of the two ops and
320 // then concatenate the per-quad data.
Brian Salomon1d835422019-03-13 16:11:44 -0400321 fColorType = SkTMax(fColorType, that->fColorType);
Michael Ludwig69858532018-11-28 15:34:34 -0500322
323 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
324 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
325 // 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 -0400326 if (upgradeToCoverageAAOnMerge) {
Michael Ludwig69858532018-11-28 15:34:34 -0500327 fHelper.setAAType(GrAAType::kCoverage);
328 }
329
Michael Ludwig425eb452019-06-27 10:13:27 -0400330 fQuads.concat(that->fQuads);
Michael Ludwig69858532018-11-28 15:34:34 -0500331 return CombineResult::kMerged;
332 }
333
334 // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
335 // But since it's avoiding the op list management, it must update the op's bounds. This is only
336 // used with quad sets, which uses the same view matrix for each quad so this assumes that the
337 // device quad type of the new quad is the same as the op's.
Robert Phillips438d9862019-11-14 12:46:05 -0500338 bool addQuad(const GrQuad& deviceQuad, const GrQuad& localQuad,
Michael Ludwig41f395d2019-05-23 13:59:45 -0400339 const SkPMColor4f& color, GrQuadAAFlags edgeAA, GrAAType aaType) {
Michael Ludwig69858532018-11-28 15:34:34 -0500340 // The new quad's aa type should be the same as the first quad's or none, except when the
341 // first quad's aa type was already downgraded to none, in which case the stored type must
342 // be lifted to back to the requested type.
Robert Phillips438d9862019-11-14 12:46:05 -0500343 if (aaType != fHelper.aaType() && aaType != GrAAType::kNone) {
344 auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(aaType,
345 fQuads.count()+1);
346 if (fQuads.count()+1 > GrQuadPerEdgeAA::QuadLimit(indexBufferOption)) {
347 // Promoting to the new aaType would've caused an overflow of the indexBuffer
348 // limit
349 return false;
Michael Ludwig69858532018-11-28 15:34:34 -0500350 }
Robert Phillips438d9862019-11-14 12:46:05 -0500351
352 // Original quad was downgraded to non-aa, lift back up to this quad's required type
353 SkASSERT(fHelper.aaType() == GrAAType::kNone);
354 fHelper.setAAType(aaType);
355 } else {
356 auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(fHelper.aaType(),
357 fQuads.count()+1);
358 if (fQuads.count()+1 > GrQuadPerEdgeAA::QuadLimit(indexBufferOption)) {
359 return false; // This op can't grow any more
360 }
Michael Ludwig69858532018-11-28 15:34:34 -0500361 }
362
Michael Ludwig69858532018-11-28 15:34:34 -0500363 // Update the bounds and add the quad to this op's storage
364 SkRect newBounds = this->bounds();
Michael Ludwig41f395d2019-05-23 13:59:45 -0400365 newBounds.joinPossiblyEmptyRect(deviceQuad.bounds());
Michael Ludwig69858532018-11-28 15:34:34 -0500366 this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
Greg Daniel5faf4742019-10-01 15:14:44 -0400367 IsHairline::kNo);
Michael Ludwig425eb452019-06-27 10:13:27 -0400368 fQuads.append(deviceQuad, { color, edgeAA }, fHelper.isTrivial() ? nullptr : &localQuad);
Robert Phillips438d9862019-11-14 12:46:05 -0500369 return true;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500370 }
371
372 struct ColorAndAA {
373 SkPMColor4f fColor;
374 GrQuadAAFlags fAAFlags;
375 };
Michael Ludwig69858532018-11-28 15:34:34 -0500376
377 Helper fHelper;
Michael Ludwig425eb452019-06-27 10:13:27 -0400378 GrQuadBuffer<ColorAndAA> fQuads;
Robert Phillips93209052019-12-03 15:42:35 -0500379 char* fPrePreparedVertices = nullptr;
Michael Ludwig69858532018-11-28 15:34:34 -0500380
Brian Salomon1d835422019-03-13 16:11:44 -0400381 ColorType fColorType;
Michael Ludwig69858532018-11-28 15:34:34 -0500382
Michael Ludwig69858532018-11-28 15:34:34 -0500383 typedef GrMeshDrawOp INHERITED;
384};
385
386} // anonymous namespace
387
Robert Phillips438d9862019-11-14 12:46:05 -0500388std::unique_ptr<GrDrawOp> GrFillRectOp::Make(GrRecordingContext* context,
389 GrPaint&& paint,
390 GrAAType aaType,
391 GrQuadAAFlags aaFlags,
392 const GrQuad& deviceQuad,
393 const GrQuad& localQuad,
394 const GrUserStencilSettings* stencil) {
Michael Ludwigd9f917b2019-05-24 12:57:55 -0400395 return FillRectOp::Make(context, std::move(paint), aaType, aaFlags, stencil,
396 deviceQuad, localQuad);
397}
398
Robert Phillips438d9862019-11-14 12:46:05 -0500399std::unique_ptr<GrDrawOp> GrFillRectOp::MakeNonAARect(GrRecordingContext* context,
400 GrPaint&& paint,
401 const SkMatrix& view,
402 const SkRect& rect,
403 const GrUserStencilSettings* stencil) {
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400404 return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, GrQuadAAFlags::kNone,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400405 stencil, GrQuad::MakeFromRect(rect, view), GrQuad(rect));
Michael Ludwig009b92e2019-02-15 16:03:53 -0500406}
407
Robert Phillips438d9862019-11-14 12:46:05 -0500408std::unique_ptr<GrDrawOp> GrFillRectOp::MakeOp(GrRecordingContext* context,
409 GrPaint&& paint,
410 GrAAType aaType,
411 const SkMatrix& viewMatrix,
412 const GrRenderTargetContext::QuadSetEntry quads[],
413 int cnt,
414 const GrUserStencilSettings* stencilSettings,
415 int* numConsumed) {
Michael Ludwig69858532018-11-28 15:34:34 -0500416 // First make a draw op for the first quad in the set
417 SkASSERT(cnt > 0);
Michael Ludwig69858532018-11-28 15:34:34 -0500418
419 paint.setColor4f(quads[0].fColor);
Robert Phillips438d9862019-11-14 12:46:05 -0500420 std::unique_ptr<GrDrawOp> op = FillRectOp::Make(
421 context, std::move(paint), aaType,
Michael Ludwige9c57d32019-02-13 13:39:39 -0500422 quads[0].fAAFlags, stencilSettings,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400423 GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
424 GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix));
Robert Phillips438d9862019-11-14 12:46:05 -0500425 FillRectOp* fillRects = op->cast<FillRectOp>();
Michael Ludwig69858532018-11-28 15:34:34 -0500426
Robert Phillips438d9862019-11-14 12:46:05 -0500427 *numConsumed = 1;
Michael Ludwig69858532018-11-28 15:34:34 -0500428 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
429 for (int i = 1; i < cnt; ++i) {
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400430 GrQuad deviceQuad = GrQuad::MakeFromRect(quads[i].fRect, viewMatrix);
Michael Ludwig69858532018-11-28 15:34:34 -0500431
432 GrAAType resolvedAA;
433 GrQuadAAFlags resolvedEdgeFlags;
Michael Ludwig0f809022019-06-04 09:14:37 -0400434 GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, deviceQuad,
435 &resolvedAA, &resolvedEdgeFlags);
Michael Ludwig69858532018-11-28 15:34:34 -0500436
Robert Phillips438d9862019-11-14 12:46:05 -0500437 if (!fillRects->addQuad(deviceQuad,
438 GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
439 quads[i].fColor, resolvedEdgeFlags, resolvedAA)) {
440 break;
441 }
442
443 (*numConsumed)++;
Michael Ludwig69858532018-11-28 15:34:34 -0500444 }
445
446 return op;
447}
448
Robert Phillips438d9862019-11-14 12:46:05 -0500449void GrFillRectOp::AddFillRectOps(GrRenderTargetContext* rtc,
450 const GrClip& clip,
451 GrRecordingContext* context,
452 GrPaint&& paint,
453 GrAAType aaType,
454 const SkMatrix& viewMatrix,
455 const GrRenderTargetContext::QuadSetEntry quads[],
456 int cnt,
457 const GrUserStencilSettings* stencilSettings) {
458
459 int offset = 0;
460 int numLeft = cnt;
461 while (numLeft) {
462 int numConsumed = 0;
463
464 std::unique_ptr<GrDrawOp> op = MakeOp(context, GrPaint::Clone(paint), aaType, viewMatrix,
465 &quads[offset], numLeft, stencilSettings,
466 &numConsumed);
467
468 offset += numConsumed;
469 numLeft -= numConsumed;
470
471 rtc->addDrawOp(clip, std::move(op));
472 }
473
474 SkASSERT(offset == cnt);
475}
Michael Ludwig69858532018-11-28 15:34:34 -0500476
477#if GR_TEST_UTILS
478
Robert Phillips438d9862019-11-14 12:46:05 -0500479uint32_t GrFillRectOp::ClassID() {
480 return FillRectOp::ClassID();
481}
482
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500483#include "src/gpu/GrDrawOpTest.h"
484#include "src/gpu/SkGr.h"
Michael Ludwig69858532018-11-28 15:34:34 -0500485
486GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
487 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
488 SkRect rect = GrTest::TestRect(random);
489
490 GrAAType aaType = GrAAType::kNone;
491 if (random->nextBool()) {
Chris Dalton6ce447a2019-06-23 18:07:38 -0600492 aaType = (numSamples > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
Michael Ludwig69858532018-11-28 15:34:34 -0500493 }
494 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
495 : GrGetRandomStencil(random, context);
496
497 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
498 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
499 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
500 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
501 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
502
503 if (random->nextBool()) {
504 if (random->nextBool()) {
Robert Phillips438d9862019-11-14 12:46:05 -0500505 // Single local matrix
506 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
507 return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
508 GrQuad::MakeFromRect(rect, viewMatrix),
509 GrQuad::MakeFromRect(rect, localMatrix), stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500510 } else {
511 // Pass local rect directly
512 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400513 return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400514 GrQuad::MakeFromRect(rect, viewMatrix),
515 GrQuad(localRect), stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500516 }
517 } else {
518 // The simplest constructor
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400519 return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400520 GrQuad::MakeFromRect(rect, viewMatrix),
521 GrQuad(rect), stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500522 }
523}
524
525#endif