blob: d46df4559e172fe54382ad7aea913feac890a89d [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"
Robert Phillips50d7d6f2020-03-04 11:12:24 -050015#include "src/gpu/GrProgramInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/gpu/SkGr.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040017#include "src/gpu/geometry/GrQuad.h"
Michael Ludwig425eb452019-06-27 10:13:27 -040018#include "src/gpu/geometry/GrQuadBuffer.h"
Michael Ludwig0f809022019-06-04 09:14:37 -040019#include "src/gpu/geometry/GrQuadUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
21#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
22#include "src/gpu/glsl/GrGLSLVarying.h"
23#include "src/gpu/ops/GrMeshDrawOp.h"
24#include "src/gpu/ops/GrQuadPerEdgeAA.h"
Robert Phillips55f681f2020-02-28 08:58:15 -050025#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
Michael Ludwig69858532018-11-28 15:34:34 -050026
27namespace {
28
29using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
30using ColorType = GrQuadPerEdgeAA::ColorType;
31
John Stiles8d9bf642020-08-12 15:07:45 -040032#if GR_TEST_UTILS
Michael Ludwig704d5402019-11-25 09:43:37 -050033static SkString dump_quad_info(int index, const GrQuad* deviceQuad,
34 const GrQuad* localQuad, const SkPMColor4f& color,
Michael Ludwigc96fc372019-01-08 15:46:15 -050035 GrQuadAAFlags aaFlags) {
Michael Ludwig704d5402019-11-25 09:43:37 -050036 GrQuad safeLocal = localQuad ? *localQuad : GrQuad();
Michael Ludwigc96fc372019-01-08 15:46:15 -050037 SkString str;
38 str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
39 " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
40 "(%.2f, %.2f, %.2f)],\n"
41 " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
42 "(%.2f, %.2f, %.2f)]\n",
43 index, color.fR, color.fG, color.fB, color.fA,
44 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
45 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
46 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
47 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
Michael Ludwig704d5402019-11-25 09:43:37 -050048 deviceQuad->x(0), deviceQuad->y(0), deviceQuad->w(0),
49 deviceQuad->x(1), deviceQuad->y(1), deviceQuad->w(1),
50 deviceQuad->x(2), deviceQuad->y(2), deviceQuad->w(2),
51 deviceQuad->x(3), deviceQuad->y(3), deviceQuad->w(3),
52 safeLocal.x(0), safeLocal.y(0), safeLocal.w(0),
53 safeLocal.x(1), safeLocal.y(1), safeLocal.w(1),
54 safeLocal.x(2), safeLocal.y(2), safeLocal.w(2),
55 safeLocal.x(3), safeLocal.y(3), safeLocal.w(3));
Michael Ludwigc96fc372019-01-08 15:46:15 -050056 return str;
57}
58#endif
Michael Ludwig69858532018-11-28 15:34:34 -050059
Michael Ludwig69858532018-11-28 15:34:34 -050060class FillRectOp final : public GrMeshDrawOp {
61private:
62 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
63
64public:
Robert Phillipsb97da532019-02-12 15:24:12 -050065 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Michael Ludwig69858532018-11-28 15:34:34 -050066 GrPaint&& paint,
67 GrAAType aaType,
Michael Ludwig6b45c5d2020-02-07 09:56:38 -050068 DrawQuad* quad,
Chris Daltonc3b67eb2020-02-10 21:09:58 -070069 const GrUserStencilSettings* stencilSettings,
70 Helper::InputFlags inputFlags) {
Michael Ludwig69858532018-11-28 15:34:34 -050071 // Clean up deviations between aaType and edgeAA
Michael Ludwig6b45c5d2020-02-07 09:56:38 -050072 GrQuadUtils::ResolveAAType(aaType, quad->fEdgeFlags, quad->fDevice,
73 &aaType, &quad->fEdgeFlags);
74 return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, quad,
Chris Daltonc3b67eb2020-02-10 21:09:58 -070075 stencilSettings, inputFlags);
Michael Ludwig69858532018-11-28 15:34:34 -050076 }
77
Michael Ludwigdcd48212019-01-08 15:28:57 -050078 // aaType is passed to Helper in the initializer list, so incongruities between aaType and
79 // edgeFlags must be resolved prior to calling this constructor.
80 FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
Chris Daltonc3b67eb2020-02-10 21:09:58 -070081 DrawQuad* quad, const GrUserStencilSettings* stencil, Helper::InputFlags inputFlags)
Michael Ludwig69858532018-11-28 15:34:34 -050082 : INHERITED(ClassID())
Chris Daltonc3b67eb2020-02-10 21:09:58 -070083 , fHelper(args, aaType, stencil, inputFlags)
Michael Ludwig425eb452019-06-27 10:13:27 -040084 , fQuads(1, !fHelper.isTrivial()) {
Michael Ludwig949ceb22020-02-07 10:14:45 -050085 // Set bounds before clipping so we don't have to worry about unioning the bounds of
86 // the two potential quads (GrQuad::bounds() is perspective-safe).
87 this->setBounds(quad->fDevice.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
88 IsHairline::kNo);
89
90 DrawQuad extra;
Michael Ludwig465864c2020-02-10 09:30:04 -050091 // Only clip when there's anti-aliasing. When non-aa, the GPU clips just fine and there's
92 // no inset/outset math that requires w > 0.
93 int count = quad->fEdgeFlags != GrQuadAAFlags::kNone ? GrQuadUtils::ClipToW0(quad, &extra)
94 : 1;
Michael Ludwig949ceb22020-02-07 10:14:45 -050095 if (count == 0) {
96 // We can't discard the op at this point, but disable AA flags so it won't go through
97 // inset/outset processing
98 quad->fEdgeFlags = GrQuadAAFlags::kNone;
99 count = 1;
100 }
101
Michael Ludwig425eb452019-06-27 10:13:27 -0400102 // Conservatively keep track of the local coordinates; it may be that the paint doesn't
103 // need them after analysis is finished. If the paint is known to be solid up front they
104 // can be skipped entirely.
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500105 fQuads.append(quad->fDevice, {paintColor, quad->fEdgeFlags},
106 fHelper.isTrivial() ? nullptr : &quad->fLocal);
Michael Ludwig949ceb22020-02-07 10:14:45 -0500107 if (count > 1) {
108 fQuads.append(extra.fDevice, { paintColor, extra.fEdgeFlags },
109 fHelper.isTrivial() ? nullptr : &extra.fLocal);
110 }
Michael Ludwig69858532018-11-28 15:34:34 -0500111 }
112
113 const char* name() const override { return "FillRectOp"; }
114
Chris Dalton1706cbf2019-05-21 19:35:29 -0600115 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500116 if (fProgramInfo) {
Chris Daltonbe457422020-03-16 18:05:03 -0600117 fProgramInfo->visitFPProxies(func);
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500118 } else {
119 return fHelper.visitProxies(func);
120 }
Michael Ludwig69858532018-11-28 15:34:34 -0500121 }
122
John Stiles8d9bf642020-08-12 15:07:45 -0400123#if GR_TEST_UTILS
John Stiles8dd1e222020-08-12 19:06:24 -0400124 SkString onDumpInfo() const override {
125 SkString str = SkStringPrintf("# draws: %u\n", fQuads.count());
Michael Ludwig69858532018-11-28 15:34:34 -0500126 str.appendf("Device quad type: %u, local quad type: %u\n",
Michael Ludwig425eb452019-06-27 10:13:27 -0400127 (uint32_t) fQuads.deviceQuadType(), (uint32_t) fQuads.localQuadType());
Michael Ludwig69858532018-11-28 15:34:34 -0500128 str += fHelper.dumpInfo();
Michael Ludwig425eb452019-06-27 10:13:27 -0400129 int i = 0;
130 auto iter = fQuads.iterator();
131 while(iter.next()) {
132 const ColorAndAA& info = iter.metadata();
133 str += dump_quad_info(i, iter.deviceQuad(), iter.localQuad(),
134 info.fColor, info.fAAFlags);
135 i++;
Michael Ludwig69858532018-11-28 15:34:34 -0500136 }
Michael Ludwig69858532018-11-28 15:34:34 -0500137 return str;
138 }
139#endif
140
Chris Dalton6ce447a2019-06-23 18:07:38 -0600141 GrProcessorSet::Analysis finalize(
142 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
143 GrClampType clampType) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500144 // Initialize aggregate color analysis with the first quad's color (which always exists)
Michael Ludwig425eb452019-06-27 10:13:27 -0400145 auto iter = fQuads.metadata();
146 SkAssertResult(iter.next());
147 GrProcessorAnalysisColor quadColors(iter->fColor);
Michael Ludwig69858532018-11-28 15:34:34 -0500148 // Then combine the colors of any additional quads (e.g. from MakeSet)
Michael Ludwig425eb452019-06-27 10:13:27 -0400149 while(iter.next()) {
150 quadColors = GrProcessorAnalysisColor::Combine(quadColors, iter->fColor);
Michael Ludwigca91e1f2018-12-10 10:44:44 -0500151 if (quadColors.isUnknown()) {
152 // No point in accumulating additional starting colors, combining cannot make it
153 // less unknown.
154 break;
155 }
Michael Ludwig69858532018-11-28 15:34:34 -0500156 }
Michael Ludwig72ab3462018-12-10 12:43:36 -0500157
158 // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
159 // then the coverage is always 1.0, so specify kNone for more optimal blending.
Robert Phillips360ec182020-03-26 13:29:50 -0400160 auto coverage = fHelper.aaType() == GrAAType::kCoverage
161 ? GrProcessorAnalysisCoverage::kSingleChannel
162 : GrProcessorAnalysisCoverage::kNone;
Brian Osman5ced0bf2019-03-15 10:15:29 -0400163 auto result = fHelper.finalizeProcessors(
Chris Dalton6ce447a2019-06-23 18:07:38 -0600164 caps, clip, hasMixedSampledCoverage, clampType, coverage, &quadColors);
Michael Ludwig69858532018-11-28 15:34:34 -0500165 // If there is a constant color after analysis, that means all of the quads should be set
166 // to the same color (even if they started out with different colors).
Michael Ludwig425eb452019-06-27 10:13:27 -0400167 iter = fQuads.metadata();
Michael Ludwig69858532018-11-28 15:34:34 -0500168 SkPMColor4f colorOverride;
169 if (quadColors.isConstant(&colorOverride)) {
Brian Osman2715bf52019-12-06 14:38:47 -0500170 fColorType = GrQuadPerEdgeAA::MinColorType(colorOverride);
Michael Ludwig425eb452019-06-27 10:13:27 -0400171 while(iter.next()) {
172 iter->fColor = colorOverride;
Michael Ludwig69858532018-11-28 15:34:34 -0500173 }
Brian Osman8fa7ab42019-03-18 10:22:42 -0400174 } else {
175 // Otherwise compute the color type needed as the max over all quads.
176 fColorType = ColorType::kNone;
Michael Ludwig425eb452019-06-27 10:13:27 -0400177 while(iter.next()) {
Brian Osman788b9162020-02-07 10:36:46 -0500178 fColorType = std::max(fColorType, GrQuadPerEdgeAA::MinColorType(iter->fColor));
Brian Osman8fa7ab42019-03-18 10:22:42 -0400179 }
Michael Ludwig69858532018-11-28 15:34:34 -0500180 }
Brian Salomon41f9c3c2019-03-25 11:06:12 -0400181 // Most SkShaders' FPs multiply their calculated color by the paint color or alpha. We want
182 // to use ColorType::kNone to optimize out that multiply. However, if there are no color
183 // FPs then were really writing a special shader for white rectangles and not saving any
184 // multiples. So in that case use bytes to avoid the extra shader (and possibly work around
185 // an ANGLE issue: crbug.com/942565).
186 if (fColorType == ColorType::kNone && !result.hasColorFragmentProcessor()) {
187 fColorType = ColorType::kByte;
188 }
Michael Ludwig69858532018-11-28 15:34:34 -0500189
190 return result;
191 }
192
193 FixedFunctionFlags fixedFunctionFlags() const override {
194 // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
195 // the helper's fixed function flags are appropriate.
196 return fHelper.fixedFunctionFlags();
197 }
198
199 DEFINE_OP_CLASS_ID
200
201private:
Robert Phillips438d9862019-11-14 12:46:05 -0500202 friend class ::GrFillRectOp; // for access to addQuad
203
204#if GR_TEST_UTILS
205 int numQuads() const final { return fQuads.count(); }
206#endif
Michael Ludwig69858532018-11-28 15:34:34 -0500207
Robert Phillips93209052019-12-03 15:42:35 -0500208 VertexSpec vertexSpec() const {
Robert Phillipsc554dcf2019-10-28 11:43:55 -0400209 auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(fHelper.aaType(),
210 fQuads.count());
211
Robert Phillips93209052019-12-03 15:42:35 -0500212 return VertexSpec(fQuads.deviceQuadType(), fColorType, fQuads.localQuadType(),
Brian Salomon2432d062020-04-16 20:48:09 -0400213 fHelper.usesLocalCoords(), GrQuadPerEdgeAA::Subset::kNo,
Robert Phillips93209052019-12-03 15:42:35 -0500214 fHelper.aaType(),
215 fHelper.compatibleWithCoverageAsAlpha(), indexBufferOption);
216 }
217
Robert Phillips2669a7b2020-03-12 12:07:19 -0400218 GrProgramInfo* programInfo() override {
219 // This Op implements its own onPrePrepareDraws so this entry point should never be called.
220 SkASSERT(0);
221 return fProgramInfo;
222 }
223
Robert Phillips4133dc42020-03-11 15:55:55 -0400224 void onCreateProgramInfo(const GrCaps* caps,
225 SkArenaAlloc* arena,
Brian Salomon8afde5f2020-04-01 16:22:00 -0400226 const GrSurfaceProxyView* writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400227 GrAppliedClip&& appliedClip,
228 const GrXferProcessor::DstProxyView& dstProxyView) override {
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500229 const VertexSpec vertexSpec = this->vertexSpec();
230
231 GrGeometryProcessor* gp = GrQuadPerEdgeAA::MakeProcessor(arena, vertexSpec);
232 SkASSERT(gp->vertexStride() == vertexSpec.vertexSize());
233
Brian Salomon8afde5f2020-04-01 16:22:00 -0400234 fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400235 std::move(appliedClip),
236 dstProxyView, gp,
237 vertexSpec.primitiveType());
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500238 }
239
Robert Phillips93209052019-12-03 15:42:35 -0500240 void onPrePrepareDraws(GrRecordingContext* context,
Brian Salomon8afde5f2020-04-01 16:22:00 -0400241 const GrSurfaceProxyView* writeView,
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500242 GrAppliedClip* clip,
243 const GrXferProcessor::DstProxyView& dstProxyView) override {
Robert Phillips93209052019-12-03 15:42:35 -0500244 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
245
246 SkASSERT(!fPrePreparedVertices);
247
248 SkArenaAlloc* arena = context->priv().recordTimeAllocator();
249
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500250 // This is equivalent to a GrOpFlushState::detachAppliedClip
Michael Ludwigd1d997e2020-06-04 15:52:44 -0400251 GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled();
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500252
Brian Salomon8afde5f2020-04-01 16:22:00 -0400253 this->createProgramInfo(context->priv().caps(), arena, writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400254 std::move(appliedClip), dstProxyView);
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500255
256 context->priv().recordProgramInfo(fProgramInfo);
257
Robert Phillips93209052019-12-03 15:42:35 -0500258 const VertexSpec vertexSpec = this->vertexSpec();
259
260 const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
261 const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
262
263 fPrePreparedVertices = arena->makeArrayDefault<char>(totalVertexSizeInBytes);
264
265 this->tessellate(vertexSpec, fPrePreparedVertices);
266 }
267
268 void tessellate(const VertexSpec& vertexSpec, char* dst) const {
269 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
270
271 GrQuadPerEdgeAA::Tessellator tessellator(vertexSpec, dst);
272 auto iter = fQuads.iterator();
273 while (iter.next()) {
274 // All entries should have local coords, or no entries should have local coords,
275 // matching !helper.isTrivial() (which is more conservative than helper.usesLocalCoords)
276 SkASSERT(iter.isLocalValid() != fHelper.isTrivial());
277 auto info = iter.metadata();
278 tessellator.append(iter.deviceQuad(), iter.localQuad(),
279 info.fColor, kEmptyDomain, info.fAAFlags);
280 }
281 }
282
283 void onPrepareDraws(Target* target) override {
284 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
285
286 const VertexSpec vertexSpec = this->vertexSpec();
287
Michael Ludwigdcd48212019-01-08 15:28:57 -0500288 // Make sure that if the op thought it was a solid color, the vertex spec does not use
289 // local coords.
290 SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
Michael Ludwig69858532018-11-28 15:34:34 -0500291
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400292 const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
293
Michael Ludwig69858532018-11-28 15:34:34 -0500294 // Fill the allocated vertex data
Robert Phillips93209052019-12-03 15:42:35 -0500295 void* vdata = target->makeVertexSpace(vertexSpec.vertexSize(), totalNumVertices,
Chris Daltondbb833b2020-03-17 12:15:46 -0600296 &fVertexBuffer, &fBaseVertex);
Michael Ludwig69858532018-11-28 15:34:34 -0500297 if (!vdata) {
298 SkDebugf("Could not allocate vertices\n");
299 return;
300 }
301
Robert Phillips93209052019-12-03 15:42:35 -0500302 if (fPrePreparedVertices) {
303 const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
304
305 memcpy(vdata, fPrePreparedVertices, totalVertexSizeInBytes);
306 } else {
307 this->tessellate(vertexSpec, (char*) vdata);
Michael Ludwig69858532018-11-28 15:34:34 -0500308 }
309
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400310 if (vertexSpec.needsIndexBuffer()) {
Chris Daltondbb833b2020-03-17 12:15:46 -0600311 fIndexBuffer = GrQuadPerEdgeAA::GetIndexBuffer(target, vertexSpec.indexBufferOption());
312 if (!fIndexBuffer) {
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400313 SkDebugf("Could not allocate indices\n");
314 return;
315 }
316 }
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700317 }
Michael Ludwig69858532018-11-28 15:34:34 -0500318
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700319 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Chris Daltondbb833b2020-03-17 12:15:46 -0600320 if (!fVertexBuffer) {
321 return;
322 }
323
324 const VertexSpec vertexSpec = this->vertexSpec();
325
326 if (vertexSpec.needsIndexBuffer() && !fIndexBuffer) {
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500327 return;
328 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500329
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500330 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400331 this->createProgramInfo(flushState);
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500332 }
333
Chris Daltondbb833b2020-03-17 12:15:46 -0600334 const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
335
Chris Dalton765ed362020-03-16 17:34:44 -0600336 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
Greg Daniel426274b2020-07-20 11:37:38 -0400337 flushState->bindBuffers(std::move(fIndexBuffer), nullptr, std::move(fVertexBuffer));
Chris Dalton765ed362020-03-16 17:34:44 -0600338 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
Chris Daltondbb833b2020-03-17 12:15:46 -0600339 GrQuadPerEdgeAA::IssueDraw(flushState->caps(), flushState->opsRenderPass(), vertexSpec, 0,
340 fQuads.count(), totalNumVertices, fBaseVertex);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700341 }
Michael Ludwig69858532018-11-28 15:34:34 -0500342
Michael Ludwig28b0c5d2019-12-19 14:51:00 -0500343 CombineResult onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*,
344 const GrCaps& caps) override {
Brian Salomon5f394272019-07-02 14:07:49 -0400345 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Michael Ludwig69858532018-11-28 15:34:34 -0500346 const auto* that = t->cast<FillRectOp>();
347
Robert Phillipsb69001f2019-10-29 12:16:35 -0400348 bool upgradeToCoverageAAOnMerge = false;
349 if (fHelper.aaType() != that->fHelper.aaType()) {
Robert Phillipsbbd459d2019-10-29 14:40:03 -0400350 if (!CanUpgradeAAOnMerge(fHelper.aaType(), that->fHelper.aaType())) {
Robert Phillipsb69001f2019-10-29 12:16:35 -0400351 return CombineResult::kCannotCombine;
352 }
353 upgradeToCoverageAAOnMerge = true;
354 }
355
Robert Phillipsbbd459d2019-10-29 14:40:03 -0400356 if (CombinedQuadCountWillOverflow(fHelper.aaType(), upgradeToCoverageAAOnMerge,
357 fQuads.count() + that->fQuads.count())) {
358 return CombineResult::kCannotCombine;
Michael Ludwig93aeba02018-12-21 09:50:31 -0500359 }
360
Michael Ludwigc96fc372019-01-08 15:46:15 -0500361 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
362 // ops together, so pass true as the last argument.
Michael Ludwig69858532018-11-28 15:34:34 -0500363 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
364 return CombineResult::kCannotCombine;
365 }
366
Michael Ludwigdcd48212019-01-08 15:28:57 -0500367 // If the paints were compatible, the trivial/solid-color state should be the same
368 SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
Michael Ludwig69858532018-11-28 15:34:34 -0500369
Michael Ludwigdcd48212019-01-08 15:28:57 -0500370 // If the processor sets are compatible, the two ops are always compatible; it just needs to
371 // adjust the state of the op to be the more general quad and aa types of the two ops and
372 // then concatenate the per-quad data.
Brian Osman788b9162020-02-07 10:36:46 -0500373 fColorType = std::max(fColorType, that->fColorType);
Michael Ludwig69858532018-11-28 15:34:34 -0500374
375 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
376 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
377 // 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 -0400378 if (upgradeToCoverageAAOnMerge) {
Michael Ludwig69858532018-11-28 15:34:34 -0500379 fHelper.setAAType(GrAAType::kCoverage);
380 }
381
Michael Ludwig425eb452019-06-27 10:13:27 -0400382 fQuads.concat(that->fQuads);
Michael Ludwig69858532018-11-28 15:34:34 -0500383 return CombineResult::kMerged;
384 }
385
Michael Ludwig949ceb22020-02-07 10:14:45 -0500386 bool canAddQuads(int numQuads, GrAAType aaType) {
Michael Ludwig69858532018-11-28 15:34:34 -0500387 // The new quad's aa type should be the same as the first quad's or none, except when the
388 // first quad's aa type was already downgraded to none, in which case the stored type must
389 // be lifted to back to the requested type.
Michael Ludwig949ceb22020-02-07 10:14:45 -0500390 int quadCount = fQuads.count() + numQuads;
Robert Phillips438d9862019-11-14 12:46:05 -0500391 if (aaType != fHelper.aaType() && aaType != GrAAType::kNone) {
Michael Ludwig949ceb22020-02-07 10:14:45 -0500392 auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(aaType, quadCount);
393 if (quadCount > GrQuadPerEdgeAA::QuadLimit(indexBufferOption)) {
Robert Phillips438d9862019-11-14 12:46:05 -0500394 // Promoting to the new aaType would've caused an overflow of the indexBuffer
395 // limit
396 return false;
Michael Ludwig69858532018-11-28 15:34:34 -0500397 }
Robert Phillips438d9862019-11-14 12:46:05 -0500398
399 // Original quad was downgraded to non-aa, lift back up to this quad's required type
400 SkASSERT(fHelper.aaType() == GrAAType::kNone);
401 fHelper.setAAType(aaType);
402 } else {
403 auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(fHelper.aaType(),
Michael Ludwig949ceb22020-02-07 10:14:45 -0500404 quadCount);
405 if (quadCount > GrQuadPerEdgeAA::QuadLimit(indexBufferOption)) {
Robert Phillips438d9862019-11-14 12:46:05 -0500406 return false; // This op can't grow any more
407 }
Michael Ludwig69858532018-11-28 15:34:34 -0500408 }
409
Michael Ludwig949ceb22020-02-07 10:14:45 -0500410 return true;
411 }
412
413 // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
414 // But since it's avoiding the op list management, it must update the op's bounds.
415 bool addQuad(DrawQuad* quad, const SkPMColor4f& color, GrAAType aaType) {
Michael Ludwig69858532018-11-28 15:34:34 -0500416 SkRect newBounds = this->bounds();
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500417 newBounds.joinPossiblyEmptyRect(quad->fDevice.bounds());
Michael Ludwig949ceb22020-02-07 10:14:45 -0500418
419 DrawQuad extra;
Michael Ludwig465864c2020-02-10 09:30:04 -0500420 int count = quad->fEdgeFlags != GrQuadAAFlags::kNone ? GrQuadUtils::ClipToW0(quad, &extra)
421 : 1;
Michael Ludwig949ceb22020-02-07 10:14:45 -0500422 if (count == 0 ) {
423 // Just skip the append (trivial success)
424 return true;
425 } else if (!this->canAddQuads(count, aaType)) {
426 // Not enough room in the index buffer for the AA type
427 return false;
428 } else {
429 // Can actually add the 1 or 2 quads representing the draw
430 fQuads.append(quad->fDevice, { color, quad->fEdgeFlags },
431 fHelper.isTrivial() ? nullptr : &quad->fLocal);
432 if (count > 1) {
433 fQuads.append(extra.fDevice, { color, extra.fEdgeFlags },
434 fHelper.isTrivial() ? nullptr : &extra.fLocal);
435 }
436 // Update the bounds
437 this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
438 IsHairline::kNo);
439 return true;
440 }
Michael Ludwigc96fc372019-01-08 15:46:15 -0500441 }
442
443 struct ColorAndAA {
444 SkPMColor4f fColor;
445 GrQuadAAFlags fAAFlags;
446 };
Michael Ludwig69858532018-11-28 15:34:34 -0500447
448 Helper fHelper;
Michael Ludwig425eb452019-06-27 10:13:27 -0400449 GrQuadBuffer<ColorAndAA> fQuads;
Robert Phillips93209052019-12-03 15:42:35 -0500450 char* fPrePreparedVertices = nullptr;
Michael Ludwig69858532018-11-28 15:34:34 -0500451
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500452 GrProgramInfo* fProgramInfo = nullptr;
453 ColorType fColorType;
Michael Ludwig69858532018-11-28 15:34:34 -0500454
Chris Daltondbb833b2020-03-17 12:15:46 -0600455 sk_sp<const GrBuffer> fVertexBuffer;
456 sk_sp<const GrBuffer> fIndexBuffer;
457 int fBaseVertex;
458
Michael Ludwig69858532018-11-28 15:34:34 -0500459 typedef GrMeshDrawOp INHERITED;
460};
461
462} // anonymous namespace
463
Robert Phillips438d9862019-11-14 12:46:05 -0500464std::unique_ptr<GrDrawOp> GrFillRectOp::Make(GrRecordingContext* context,
465 GrPaint&& paint,
466 GrAAType aaType,
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500467 DrawQuad* quad,
Chris Daltonc3b67eb2020-02-10 21:09:58 -0700468 const GrUserStencilSettings* stencil,
469 InputFlags inputFlags) {
470 return FillRectOp::Make(context, std::move(paint), aaType, std::move(quad), stencil,
471 inputFlags);
Michael Ludwigd9f917b2019-05-24 12:57:55 -0400472}
473
Robert Phillips438d9862019-11-14 12:46:05 -0500474std::unique_ptr<GrDrawOp> GrFillRectOp::MakeNonAARect(GrRecordingContext* context,
475 GrPaint&& paint,
476 const SkMatrix& view,
477 const SkRect& rect,
478 const GrUserStencilSettings* stencil) {
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500479 DrawQuad quad{GrQuad::MakeFromRect(rect, view), GrQuad(rect), GrQuadAAFlags::kNone};
Chris Daltonc3b67eb2020-02-10 21:09:58 -0700480 return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, &quad, stencil,
481 InputFlags::kNone);
Michael Ludwig009b92e2019-02-15 16:03:53 -0500482}
483
Robert Phillips438d9862019-11-14 12:46:05 -0500484std::unique_ptr<GrDrawOp> GrFillRectOp::MakeOp(GrRecordingContext* context,
485 GrPaint&& paint,
486 GrAAType aaType,
487 const SkMatrix& viewMatrix,
488 const GrRenderTargetContext::QuadSetEntry quads[],
489 int cnt,
490 const GrUserStencilSettings* stencilSettings,
491 int* numConsumed) {
Michael Ludwig69858532018-11-28 15:34:34 -0500492 // First make a draw op for the first quad in the set
493 SkASSERT(cnt > 0);
Michael Ludwig69858532018-11-28 15:34:34 -0500494
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500495 DrawQuad quad{GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
496 GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix),
497 quads[0].fAAFlags};
Michael Ludwig69858532018-11-28 15:34:34 -0500498 paint.setColor4f(quads[0].fColor);
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500499 std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
Chris Daltonc3b67eb2020-02-10 21:09:58 -0700500 &quad, stencilSettings, InputFlags::kNone);
Robert Phillips438d9862019-11-14 12:46:05 -0500501 FillRectOp* fillRects = op->cast<FillRectOp>();
Michael Ludwig69858532018-11-28 15:34:34 -0500502
Robert Phillips438d9862019-11-14 12:46:05 -0500503 *numConsumed = 1;
Michael Ludwig69858532018-11-28 15:34:34 -0500504 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
505 for (int i = 1; i < cnt; ++i) {
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500506 quad = {GrQuad::MakeFromRect(quads[i].fRect, viewMatrix),
507 GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
508 quads[i].fAAFlags};
Michael Ludwig69858532018-11-28 15:34:34 -0500509
510 GrAAType resolvedAA;
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500511 GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, quad.fDevice,
512 &resolvedAA, &quad.fEdgeFlags);
Michael Ludwig69858532018-11-28 15:34:34 -0500513
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500514 if (!fillRects->addQuad(&quad, quads[i].fColor, resolvedAA)) {
Robert Phillips438d9862019-11-14 12:46:05 -0500515 break;
516 }
517
518 (*numConsumed)++;
Michael Ludwig69858532018-11-28 15:34:34 -0500519 }
520
521 return op;
522}
523
Robert Phillips438d9862019-11-14 12:46:05 -0500524void GrFillRectOp::AddFillRectOps(GrRenderTargetContext* rtc,
Michael Ludwig7c12e282020-05-29 09:54:07 -0400525 const GrClip* clip,
Robert Phillips438d9862019-11-14 12:46:05 -0500526 GrRecordingContext* context,
527 GrPaint&& paint,
528 GrAAType aaType,
529 const SkMatrix& viewMatrix,
530 const GrRenderTargetContext::QuadSetEntry quads[],
531 int cnt,
532 const GrUserStencilSettings* stencilSettings) {
533
534 int offset = 0;
535 int numLeft = cnt;
536 while (numLeft) {
537 int numConsumed = 0;
538
539 std::unique_ptr<GrDrawOp> op = MakeOp(context, GrPaint::Clone(paint), aaType, viewMatrix,
540 &quads[offset], numLeft, stencilSettings,
541 &numConsumed);
542
543 offset += numConsumed;
544 numLeft -= numConsumed;
545
546 rtc->addDrawOp(clip, std::move(op));
547 }
548
549 SkASSERT(offset == cnt);
550}
Michael Ludwig69858532018-11-28 15:34:34 -0500551
552#if GR_TEST_UTILS
553
Robert Phillips438d9862019-11-14 12:46:05 -0500554uint32_t GrFillRectOp::ClassID() {
555 return FillRectOp::ClassID();
556}
557
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500558#include "src/gpu/GrDrawOpTest.h"
559#include "src/gpu/SkGr.h"
Michael Ludwig69858532018-11-28 15:34:34 -0500560
561GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
562 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
563 SkRect rect = GrTest::TestRect(random);
564
565 GrAAType aaType = GrAAType::kNone;
566 if (random->nextBool()) {
Chris Dalton6ce447a2019-06-23 18:07:38 -0600567 aaType = (numSamples > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
Michael Ludwig69858532018-11-28 15:34:34 -0500568 }
569 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
570 : GrGetRandomStencil(random, context);
571
572 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
573 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
574 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
575 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
576 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
577
578 if (random->nextBool()) {
579 if (random->nextBool()) {
Robert Phillips438d9862019-11-14 12:46:05 -0500580 // Single local matrix
581 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500582 DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix),
583 GrQuad::MakeFromRect(rect, localMatrix), aaFlags};
584 return GrFillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500585 } else {
586 // Pass local rect directly
587 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500588 DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix),
589 GrQuad(localRect), aaFlags};
590 return GrFillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500591 }
592 } else {
593 // The simplest constructor
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500594 DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(rect), aaFlags};
595 return GrFillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500596 }
597}
598
599#endif