blob: b08899162c38e61db6d86cca4ac5d44d6889655d [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
Robert Phillipsfbf02142021-09-01 16:31:34 -04008#include "src/gpu/ops/FillRectOp.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"
Robert Phillipse40495d2021-07-20 09:40:13 -040014#include "src/gpu/GrOpsTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/gpu/GrPaint.h"
Robert Phillips50d7d6f2020-03-04 11:12:24 -050016#include "src/gpu/GrProgramInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/SkGr.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040018#include "src/gpu/geometry/GrQuad.h"
Michael Ludwig425eb452019-06-27 10:13:27 -040019#include "src/gpu/geometry/GrQuadBuffer.h"
Michael Ludwig0f809022019-06-04 09:14:37 -040020#include "src/gpu/geometry/GrQuadUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/gpu/glsl/GrGLSLVarying.h"
23#include "src/gpu/ops/GrMeshDrawOp.h"
Robert Phillips55f681f2020-02-28 08:58:15 -050024#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
Robert Phillipsef80d7b2021-09-14 16:10:56 -040025#include "src/gpu/ops/QuadPerEdgeAA.h"
Robert Phillips4dca8312021-07-28 15:13:20 -040026#include "src/gpu/v1/SurfaceDrawContext_v1.h"
Michael Ludwig69858532018-11-28 15:34:34 -050027
28namespace {
29
Robert Phillipsef80d7b2021-09-14 16:10:56 -040030using VertexSpec = skgpu::v1::QuadPerEdgeAA::VertexSpec;
31using ColorType = skgpu::v1::QuadPerEdgeAA::ColorType;
32using Subset = skgpu::v1::QuadPerEdgeAA::Subset;
Michael Ludwig69858532018-11-28 15:34:34 -050033
John Stiles8d9bf642020-08-12 15:07:45 -040034#if GR_TEST_UTILS
Robert Phillipsfbf02142021-09-01 16:31:34 -040035SkString dump_quad_info(int index, const GrQuad* deviceQuad,
36 const GrQuad* localQuad, const SkPMColor4f& color,
37 GrQuadAAFlags aaFlags) {
Michael Ludwig704d5402019-11-25 09:43:37 -050038 GrQuad safeLocal = localQuad ? *localQuad : GrQuad();
Michael Ludwigc96fc372019-01-08 15:46:15 -050039 SkString str;
40 str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
41 " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
42 "(%.2f, %.2f, %.2f)],\n"
43 " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
44 "(%.2f, %.2f, %.2f)]\n",
45 index, color.fR, color.fG, color.fB, color.fA,
46 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
47 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
48 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
49 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
Michael Ludwig704d5402019-11-25 09:43:37 -050050 deviceQuad->x(0), deviceQuad->y(0), deviceQuad->w(0),
51 deviceQuad->x(1), deviceQuad->y(1), deviceQuad->w(1),
52 deviceQuad->x(2), deviceQuad->y(2), deviceQuad->w(2),
53 deviceQuad->x(3), deviceQuad->y(3), deviceQuad->w(3),
54 safeLocal.x(0), safeLocal.y(0), safeLocal.w(0),
55 safeLocal.x(1), safeLocal.y(1), safeLocal.w(1),
56 safeLocal.x(2), safeLocal.y(2), safeLocal.w(2),
57 safeLocal.x(3), safeLocal.y(3), safeLocal.w(3));
Michael Ludwigc96fc372019-01-08 15:46:15 -050058 return str;
59}
60#endif
Michael Ludwig69858532018-11-28 15:34:34 -050061
Robert Phillipsfbf02142021-09-01 16:31:34 -040062class FillRectOpImpl final : public GrMeshDrawOp {
Michael Ludwig69858532018-11-28 15:34:34 -050063private:
64 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
65
66public:
Herb Derbyc76d4092020-10-07 16:46:15 -040067 static GrOp::Owner Make(GrRecordingContext* context,
68 GrPaint&& paint,
69 GrAAType aaType,
70 DrawQuad* quad,
71 const GrUserStencilSettings* stencilSettings,
72 Helper::InputFlags inputFlags) {
Michael Ludwig69858532018-11-28 15:34:34 -050073 // Clean up deviations between aaType and edgeAA
Michael Ludwig6b45c5d2020-02-07 09:56:38 -050074 GrQuadUtils::ResolveAAType(aaType, quad->fEdgeFlags, quad->fDevice,
75 &aaType, &quad->fEdgeFlags);
Robert Phillipsfbf02142021-09-01 16:31:34 -040076 return Helper::FactoryHelper<FillRectOpImpl>(context, std::move(paint), aaType, quad,
77 stencilSettings, inputFlags);
Michael Ludwig69858532018-11-28 15:34:34 -050078 }
79
Michael Ludwigdcd48212019-01-08 15:28:57 -050080 // aaType is passed to Helper in the initializer list, so incongruities between aaType and
81 // edgeFlags must be resolved prior to calling this constructor.
Robert Phillipsfbf02142021-09-01 16:31:34 -040082 FillRectOpImpl(GrProcessorSet* processorSet, SkPMColor4f paintColor, GrAAType aaType,
83 DrawQuad* quad, const GrUserStencilSettings* stencil,
84 Helper::InputFlags inputFlags)
Michael Ludwig69858532018-11-28 15:34:34 -050085 : INHERITED(ClassID())
Herb Derbyc76d4092020-10-07 16:46:15 -040086 , fHelper(processorSet, aaType, stencil, inputFlags)
Michael Ludwig425eb452019-06-27 10:13:27 -040087 , fQuads(1, !fHelper.isTrivial()) {
Michael Ludwig949ceb22020-02-07 10:14:45 -050088 // Set bounds before clipping so we don't have to worry about unioning the bounds of
89 // the two potential quads (GrQuad::bounds() is perspective-safe).
Michael Ludwig575c9212021-07-13 11:09:52 -040090 bool hairline = GrQuadUtils::WillUseHairline(quad->fDevice, aaType, quad->fEdgeFlags);
Michael Ludwig949ceb22020-02-07 10:14:45 -050091 this->setBounds(quad->fDevice.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
Michael Ludwig575c9212021-07-13 11:09:52 -040092 hairline ? IsHairline::kYes : IsHairline::kNo);
Michael Ludwig949ceb22020-02-07 10:14:45 -050093 DrawQuad extra;
Michael Ludwig65299902021-05-13 12:02:23 -040094 // Always crop to W>0 to remain consistent with GrQuad::bounds()
95 int count = GrQuadUtils::ClipToW0(quad, &extra);
Michael Ludwig949ceb22020-02-07 10:14:45 -050096 if (count == 0) {
97 // We can't discard the op at this point, but disable AA flags so it won't go through
98 // inset/outset processing
99 quad->fEdgeFlags = GrQuadAAFlags::kNone;
100 count = 1;
101 }
102
Michael Ludwig425eb452019-06-27 10:13:27 -0400103 // Conservatively keep track of the local coordinates; it may be that the paint doesn't
104 // need them after analysis is finished. If the paint is known to be solid up front they
105 // can be skipped entirely.
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500106 fQuads.append(quad->fDevice, {paintColor, quad->fEdgeFlags},
107 fHelper.isTrivial() ? nullptr : &quad->fLocal);
Michael Ludwig949ceb22020-02-07 10:14:45 -0500108 if (count > 1) {
109 fQuads.append(extra.fDevice, { paintColor, extra.fEdgeFlags },
110 fHelper.isTrivial() ? nullptr : &extra.fLocal);
111 }
Michael Ludwig69858532018-11-28 15:34:34 -0500112 }
113
114 const char* name() const override { return "FillRectOp"; }
115
Robert Phillips294723d2021-06-17 09:23:58 -0400116 void visitProxies(const GrVisitProxyFunc& func) const override {
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500117 if (fProgramInfo) {
Chris Daltonbe457422020-03-16 18:05:03 -0600118 fProgramInfo->visitFPProxies(func);
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500119 } else {
120 return fHelper.visitProxies(func);
121 }
Michael Ludwig69858532018-11-28 15:34:34 -0500122 }
123
Chris Dalton57ab06c2021-04-22 12:57:28 -0600124 GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
125 GrClampType clampType) override {
Michael Ludwig69858532018-11-28 15:34:34 -0500126 // Initialize aggregate color analysis with the first quad's color (which always exists)
Michael Ludwig425eb452019-06-27 10:13:27 -0400127 auto iter = fQuads.metadata();
128 SkAssertResult(iter.next());
129 GrProcessorAnalysisColor quadColors(iter->fColor);
Michael Ludwig69858532018-11-28 15:34:34 -0500130 // Then combine the colors of any additional quads (e.g. from MakeSet)
Michael Ludwig425eb452019-06-27 10:13:27 -0400131 while(iter.next()) {
132 quadColors = GrProcessorAnalysisColor::Combine(quadColors, iter->fColor);
Michael Ludwigca91e1f2018-12-10 10:44:44 -0500133 if (quadColors.isUnknown()) {
134 // No point in accumulating additional starting colors, combining cannot make it
135 // less unknown.
136 break;
137 }
Michael Ludwig69858532018-11-28 15:34:34 -0500138 }
Michael Ludwig72ab3462018-12-10 12:43:36 -0500139
140 // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
141 // then the coverage is always 1.0, so specify kNone for more optimal blending.
Robert Phillips360ec182020-03-26 13:29:50 -0400142 auto coverage = fHelper.aaType() == GrAAType::kCoverage
143 ? GrProcessorAnalysisCoverage::kSingleChannel
144 : GrProcessorAnalysisCoverage::kNone;
Chris Dalton57ab06c2021-04-22 12:57:28 -0600145 auto result = fHelper.finalizeProcessors(caps, clip, 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).
Michael Ludwig425eb452019-06-27 10:13:27 -0400148 iter = fQuads.metadata();
Michael Ludwig69858532018-11-28 15:34:34 -0500149 SkPMColor4f colorOverride;
150 if (quadColors.isConstant(&colorOverride)) {
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400151 fColorType = skgpu::v1::QuadPerEdgeAA::MinColorType(colorOverride);
Michael Ludwig425eb452019-06-27 10:13:27 -0400152 while(iter.next()) {
153 iter->fColor = colorOverride;
Michael Ludwig69858532018-11-28 15:34:34 -0500154 }
Brian Osman8fa7ab42019-03-18 10:22:42 -0400155 } else {
156 // Otherwise compute the color type needed as the max over all quads.
157 fColorType = ColorType::kNone;
Michael Ludwig425eb452019-06-27 10:13:27 -0400158 while(iter.next()) {
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400159 fColorType = std::max(fColorType,
160 skgpu::v1::QuadPerEdgeAA::MinColorType(iter->fColor));
Brian Osman8fa7ab42019-03-18 10:22:42 -0400161 }
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:
Robert Phillipsfbf02142021-09-01 16:31:34 -0400184 friend class skgpu::v1::FillRectOp; // for access to addQuad
Robert Phillips438d9862019-11-14 12:46:05 -0500185
186#if GR_TEST_UTILS
187 int numQuads() const final { return fQuads.count(); }
188#endif
Michael Ludwig69858532018-11-28 15:34:34 -0500189
Brian Salomonb8c4add2021-06-28 09:20:44 -0400190 VertexSpec vertexSpec() const {
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400191 auto indexBufferOption = skgpu::v1::QuadPerEdgeAA::CalcIndexBufferOption(fHelper.aaType(),
192 fQuads.count());
Robert Phillipsc554dcf2019-10-28 11:43:55 -0400193
Robert Phillips93209052019-12-03 15:42:35 -0500194 return VertexSpec(fQuads.deviceQuadType(), fColorType, fQuads.localQuadType(),
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400195 fHelper.usesLocalCoords(), Subset::kNo, fHelper.aaType(),
Robert Phillips93209052019-12-03 15:42:35 -0500196 fHelper.compatibleWithCoverageAsAlpha(), indexBufferOption);
197 }
198
Robert Phillips2669a7b2020-03-12 12:07:19 -0400199 GrProgramInfo* programInfo() override {
Robert Phillips2669a7b2020-03-12 12:07:19 -0400200 return fProgramInfo;
201 }
202
Robert Phillips4133dc42020-03-11 15:55:55 -0400203 void onCreateProgramInfo(const GrCaps* caps,
204 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500205 const GrSurfaceProxyView& writeView,
Chris Dalton6aaf00f2021-07-13 13:26:39 -0600206 bool usesMSAASurface,
Robert Phillips4133dc42020-03-11 15:55:55 -0400207 GrAppliedClip&& appliedClip,
John Stiles52cb1d02021-06-02 11:58:05 -0400208 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500209 GrXferBarrierFlags renderPassXferBarriers,
210 GrLoadOp colorLoadOp) override {
Brian Salomonb8c4add2021-06-28 09:20:44 -0400211 const VertexSpec vertexSpec = this->vertexSpec();
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500212
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400213 GrGeometryProcessor* gp = skgpu::v1::QuadPerEdgeAA::MakeProcessor(arena, vertexSpec);
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500214 SkASSERT(gp->vertexStride() == vertexSpec.vertexSize());
215
Chris Dalton2a26c502021-08-26 10:05:11 -0600216 fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, usesMSAASurface,
Robert Phillips4133dc42020-03-11 15:55:55 -0400217 std::move(appliedClip),
218 dstProxyView, gp,
Greg Danield358cbe2020-09-11 09:33:54 -0400219 vertexSpec.primitiveType(),
Greg Daniel42dbca52020-11-20 10:22:43 -0500220 renderPassXferBarriers, colorLoadOp);
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500221 }
222
Robert Phillips473a8482020-10-20 10:44:15 -0400223 void onPrePrepareDraws(GrRecordingContext* rContext,
Adlai Hollere2296f72020-11-19 13:41:26 -0500224 const GrSurfaceProxyView& writeView,
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500225 GrAppliedClip* clip,
John Stiles52cb1d02021-06-02 11:58:05 -0400226 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500227 GrXferBarrierFlags renderPassXferBarriers,
228 GrLoadOp colorLoadOp) override {
Robert Phillips93209052019-12-03 15:42:35 -0500229 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
230
231 SkASSERT(!fPrePreparedVertices);
232
Robert Phillips473a8482020-10-20 10:44:15 -0400233 INHERITED::onPrePrepareDraws(rContext, writeView, clip, dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500234 renderPassXferBarriers, colorLoadOp);
Robert Phillips93209052019-12-03 15:42:35 -0500235
Robert Phillips473a8482020-10-20 10:44:15 -0400236 SkArenaAlloc* arena = rContext->priv().recordTimeAllocator();
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500237
Brian Salomonb8c4add2021-06-28 09:20:44 -0400238 const VertexSpec vertexSpec = this->vertexSpec();
Robert Phillips93209052019-12-03 15:42:35 -0500239
240 const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
241 const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
242
243 fPrePreparedVertices = arena->makeArrayDefault<char>(totalVertexSizeInBytes);
244
245 this->tessellate(vertexSpec, fPrePreparedVertices);
246 }
247
248 void tessellate(const VertexSpec& vertexSpec, char* dst) const {
249 static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
250
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400251 skgpu::v1::QuadPerEdgeAA::Tessellator tessellator(vertexSpec, dst);
Robert Phillips93209052019-12-03 15:42:35 -0500252 auto iter = fQuads.iterator();
253 while (iter.next()) {
254 // All entries should have local coords, or no entries should have local coords,
255 // matching !helper.isTrivial() (which is more conservative than helper.usesLocalCoords)
256 SkASSERT(iter.isLocalValid() != fHelper.isTrivial());
257 auto info = iter.metadata();
258 tessellator.append(iter.deviceQuad(), iter.localQuad(),
259 info.fColor, kEmptyDomain, info.fAAFlags);
260 }
261 }
262
Robert Phillips71143952021-06-17 14:55:07 -0400263 void onPrepareDraws(GrMeshDrawTarget* target) override {
Robert Phillips93209052019-12-03 15:42:35 -0500264 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
265
Brian Salomonb8c4add2021-06-28 09:20:44 -0400266 const VertexSpec vertexSpec = this->vertexSpec();
Robert Phillips93209052019-12-03 15:42:35 -0500267
Michael Ludwigdcd48212019-01-08 15:28:57 -0500268 // Make sure that if the op thought it was a solid color, the vertex spec does not use
269 // local coords.
270 SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
Michael Ludwig69858532018-11-28 15:34:34 -0500271
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400272 const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
273
Michael Ludwig69858532018-11-28 15:34:34 -0500274 // Fill the allocated vertex data
Robert Phillips93209052019-12-03 15:42:35 -0500275 void* vdata = target->makeVertexSpace(vertexSpec.vertexSize(), totalNumVertices,
Chris Daltondbb833b2020-03-17 12:15:46 -0600276 &fVertexBuffer, &fBaseVertex);
Michael Ludwig69858532018-11-28 15:34:34 -0500277 if (!vdata) {
278 SkDebugf("Could not allocate vertices\n");
279 return;
280 }
281
Robert Phillips93209052019-12-03 15:42:35 -0500282 if (fPrePreparedVertices) {
283 const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
284
285 memcpy(vdata, fPrePreparedVertices, totalVertexSizeInBytes);
286 } else {
287 this->tessellate(vertexSpec, (char*) vdata);
Michael Ludwig69858532018-11-28 15:34:34 -0500288 }
289
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400290 if (vertexSpec.needsIndexBuffer()) {
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400291 fIndexBuffer = skgpu::v1::QuadPerEdgeAA::GetIndexBuffer(target,
292 vertexSpec.indexBufferOption());
Chris Daltondbb833b2020-03-17 12:15:46 -0600293 if (!fIndexBuffer) {
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400294 SkDebugf("Could not allocate indices\n");
295 return;
296 }
297 }
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700298 }
Michael Ludwig69858532018-11-28 15:34:34 -0500299
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700300 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Chris Daltondbb833b2020-03-17 12:15:46 -0600301 if (!fVertexBuffer) {
302 return;
303 }
304
Brian Salomonb8c4add2021-06-28 09:20:44 -0400305 const VertexSpec vertexSpec = this->vertexSpec();
Chris Daltondbb833b2020-03-17 12:15:46 -0600306
307 if (vertexSpec.needsIndexBuffer() && !fIndexBuffer) {
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500308 return;
309 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500310
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500311 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400312 this->createProgramInfo(flushState);
Robert Phillips50d7d6f2020-03-04 11:12:24 -0500313 }
314
Chris Daltondbb833b2020-03-17 12:15:46 -0600315 const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
316
Chris Dalton765ed362020-03-16 17:34:44 -0600317 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
Greg Daniel426274b2020-07-20 11:37:38 -0400318 flushState->bindBuffers(std::move(fIndexBuffer), nullptr, std::move(fVertexBuffer));
Robert Phillips787fd9d2021-03-22 14:48:09 -0400319 flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400320 skgpu::v1::QuadPerEdgeAA::IssueDraw(flushState->caps(), flushState->opsRenderPass(),
321 vertexSpec, 0, fQuads.count(), totalNumVertices,
322 fBaseVertex);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700323 }
Michael Ludwig69858532018-11-28 15:34:34 -0500324
Herb Derbye25c3002020-10-27 15:57:27 -0400325 CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
Brian Salomon5f394272019-07-02 14:07:49 -0400326 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Robert Phillipsfbf02142021-09-01 16:31:34 -0400327 auto that = t->cast<FillRectOpImpl>();
Michael Ludwig69858532018-11-28 15:34:34 -0500328
Robert Phillipsb69001f2019-10-29 12:16:35 -0400329 bool upgradeToCoverageAAOnMerge = false;
330 if (fHelper.aaType() != that->fHelper.aaType()) {
Robert Phillipsbbd459d2019-10-29 14:40:03 -0400331 if (!CanUpgradeAAOnMerge(fHelper.aaType(), that->fHelper.aaType())) {
Robert Phillipsb69001f2019-10-29 12:16:35 -0400332 return CombineResult::kCannotCombine;
333 }
334 upgradeToCoverageAAOnMerge = true;
335 }
336
Robert Phillipsbbd459d2019-10-29 14:40:03 -0400337 if (CombinedQuadCountWillOverflow(fHelper.aaType(), upgradeToCoverageAAOnMerge,
338 fQuads.count() + that->fQuads.count())) {
339 return CombineResult::kCannotCombine;
Michael Ludwig93aeba02018-12-21 09:50:31 -0500340 }
341
Michael Ludwigc96fc372019-01-08 15:46:15 -0500342 // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
343 // ops together, so pass true as the last argument.
Michael Ludwig69858532018-11-28 15:34:34 -0500344 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
345 return CombineResult::kCannotCombine;
346 }
347
Michael Ludwigdcd48212019-01-08 15:28:57 -0500348 // If the paints were compatible, the trivial/solid-color state should be the same
349 SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
Michael Ludwig69858532018-11-28 15:34:34 -0500350
Michael Ludwigdcd48212019-01-08 15:28:57 -0500351 // If the processor sets are compatible, the two ops are always compatible; it just needs to
352 // adjust the state of the op to be the more general quad and aa types of the two ops and
353 // then concatenate the per-quad data.
Brian Osman788b9162020-02-07 10:36:46 -0500354 fColorType = std::max(fColorType, that->fColorType);
Michael Ludwig69858532018-11-28 15:34:34 -0500355
356 // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
357 // types to be none and coverage, in which case this op's aa type must be lifted to coverage
358 // 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 -0400359 if (upgradeToCoverageAAOnMerge) {
Michael Ludwig69858532018-11-28 15:34:34 -0500360 fHelper.setAAType(GrAAType::kCoverage);
361 }
362
Michael Ludwig425eb452019-06-27 10:13:27 -0400363 fQuads.concat(that->fQuads);
Michael Ludwig69858532018-11-28 15:34:34 -0500364 return CombineResult::kMerged;
365 }
366
John Stilesaf366522020-08-13 09:57:34 -0400367#if GR_TEST_UTILS
368 SkString onDumpInfo() const override {
369 SkString str = SkStringPrintf("# draws: %u\n", fQuads.count());
370 str.appendf("Device quad type: %u, local quad type: %u\n",
371 (uint32_t) fQuads.deviceQuadType(), (uint32_t) fQuads.localQuadType());
372 str += fHelper.dumpInfo();
373 int i = 0;
374 auto iter = fQuads.iterator();
375 while(iter.next()) {
376 const ColorAndAA& info = iter.metadata();
377 str += dump_quad_info(i, iter.deviceQuad(), iter.localQuad(),
378 info.fColor, info.fAAFlags);
379 i++;
380 }
381 return str;
382 }
383#endif
384
Brian Salomonb8c4add2021-06-28 09:20:44 -0400385 bool canAddQuads(int numQuads, GrAAType aaType) {
Michael Ludwig69858532018-11-28 15:34:34 -0500386 // The new quad's aa type should be the same as the first quad's or none, except when the
387 // first quad's aa type was already downgraded to none, in which case the stored type must
388 // be lifted to back to the requested type.
Michael Ludwig949ceb22020-02-07 10:14:45 -0500389 int quadCount = fQuads.count() + numQuads;
Robert Phillips438d9862019-11-14 12:46:05 -0500390 if (aaType != fHelper.aaType() && aaType != GrAAType::kNone) {
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400391 auto indexBufferOption = skgpu::v1::QuadPerEdgeAA::CalcIndexBufferOption(aaType,
392 quadCount);
393 if (quadCount > skgpu::v1::QuadPerEdgeAA::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 {
Robert Phillipsef80d7b2021-09-14 16:10:56 -0400403 auto indexBufferOption = skgpu::v1::QuadPerEdgeAA::CalcIndexBufferOption(
404 fHelper.aaType(), quadCount);
405 if (quadCount > skgpu::v1::QuadPerEdgeAA::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.
Brian Salomonb8c4add2021-06-28 09:20:44 -0400415 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;
Brian Salomonb8c4add2021-06-28 09:20:44 -0400425 } else if (!this->canAddQuads(count, aaType)) {
Michael Ludwig949ceb22020-02-07 10:14:45 -0500426 // 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
John Stiles7571f9e2020-09-02 22:42:33 -0400459 using INHERITED = GrMeshDrawOp;
Michael Ludwig69858532018-11-28 15:34:34 -0500460};
461
462} // anonymous namespace
463
Robert Phillipsfbf02142021-09-01 16:31:34 -0400464namespace skgpu::v1 {
465
466GrOp::Owner FillRectOp::Make(GrRecordingContext* context,
467 GrPaint&& paint,
468 GrAAType aaType,
469 DrawQuad* quad,
470 const GrUserStencilSettings* stencil,
471 InputFlags inputFlags) {
472 return FillRectOpImpl::Make(context, std::move(paint), aaType, std::move(quad), stencil,
473 inputFlags);
474}
475
476GrOp::Owner FillRectOp::MakeNonAARect(GrRecordingContext* context,
477 GrPaint&& paint,
478 const SkMatrix& view,
479 const SkRect& rect,
480 const GrUserStencilSettings* stencil) {
481 DrawQuad quad{GrQuad::MakeFromRect(rect, view), GrQuad(rect), GrQuadAAFlags::kNone};
482 return FillRectOpImpl::Make(context, std::move(paint), GrAAType::kNone, &quad, stencil,
483 InputFlags::kNone);
484}
485
486GrOp::Owner FillRectOp::MakeOp(GrRecordingContext* context,
Herb Derbyc76d4092020-10-07 16:46:15 -0400487 GrPaint&& paint,
488 GrAAType aaType,
Robert Phillipsfbf02142021-09-01 16:31:34 -0400489 const SkMatrix& viewMatrix,
490 const GrQuadSetEntry quads[],
491 int cnt,
492 const GrUserStencilSettings* stencilSettings,
493 int* numConsumed) {
Michael Ludwig69858532018-11-28 15:34:34 -0500494 // First make a draw op for the first quad in the set
495 SkASSERT(cnt > 0);
Michael Ludwig69858532018-11-28 15:34:34 -0500496
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500497 DrawQuad quad{GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
498 GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix),
499 quads[0].fAAFlags};
Michael Ludwig69858532018-11-28 15:34:34 -0500500 paint.setColor4f(quads[0].fColor);
Herb Derbyc76d4092020-10-07 16:46:15 -0400501 GrOp::Owner op = FillRectOp::Make(context, std::move(paint), aaType,
502 &quad, stencilSettings, InputFlags::kNone);
Robert Phillipsfbf02142021-09-01 16:31:34 -0400503 auto fillRects = op->cast<FillRectOpImpl>();
Michael Ludwig69858532018-11-28 15:34:34 -0500504
Robert Phillips438d9862019-11-14 12:46:05 -0500505 *numConsumed = 1;
Michael Ludwig69858532018-11-28 15:34:34 -0500506 // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
507 for (int i = 1; i < cnt; ++i) {
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500508 quad = {GrQuad::MakeFromRect(quads[i].fRect, viewMatrix),
509 GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
510 quads[i].fAAFlags};
Michael Ludwig69858532018-11-28 15:34:34 -0500511
512 GrAAType resolvedAA;
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500513 GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, quad.fDevice,
514 &resolvedAA, &quad.fEdgeFlags);
Michael Ludwig69858532018-11-28 15:34:34 -0500515
Brian Salomonb8c4add2021-06-28 09:20:44 -0400516 if (!fillRects->addQuad(&quad, quads[i].fColor, resolvedAA)) {
Robert Phillips438d9862019-11-14 12:46:05 -0500517 break;
518 }
519
520 (*numConsumed)++;
Michael Ludwig69858532018-11-28 15:34:34 -0500521 }
522
523 return op;
524}
525
Robert Phillipsfbf02142021-09-01 16:31:34 -0400526void FillRectOp::AddFillRectOps(skgpu::v1::SurfaceDrawContext* sdc,
527 const GrClip* clip,
528 GrRecordingContext* context,
529 GrPaint&& paint,
530 GrAAType aaType,
531 const SkMatrix& viewMatrix,
532 const GrQuadSetEntry quads[],
533 int cnt,
534 const GrUserStencilSettings* stencilSettings) {
Robert Phillips438d9862019-11-14 12:46:05 -0500535
536 int offset = 0;
537 int numLeft = cnt;
538 while (numLeft) {
539 int numConsumed = 0;
540
Herb Derbyc76d4092020-10-07 16:46:15 -0400541 GrOp::Owner op = MakeOp(context, GrPaint::Clone(paint), aaType, viewMatrix,
542 &quads[offset], numLeft, stencilSettings,
543 &numConsumed);
Robert Phillips438d9862019-11-14 12:46:05 -0500544
545 offset += numConsumed;
546 numLeft -= numConsumed;
547
Robert Phillips4dca8312021-07-28 15:13:20 -0400548 sdc->addDrawOp(clip, std::move(op));
Robert Phillips438d9862019-11-14 12:46:05 -0500549 }
550
551 SkASSERT(offset == cnt);
552}
Robert Phillipsfbf02142021-09-01 16:31:34 -0400553
554} // namespace skgpu::v1
Michael Ludwig69858532018-11-28 15:34:34 -0500555
556#if GR_TEST_UTILS
557
Robert Phillipsfbf02142021-09-01 16:31:34 -0400558uint32_t skgpu::v1::FillRectOp::ClassID() {
559 return FillRectOpImpl::ClassID();
Robert Phillips438d9862019-11-14 12:46:05 -0500560}
561
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500562#include "src/gpu/GrDrawOpTest.h"
563#include "src/gpu/SkGr.h"
Michael Ludwig69858532018-11-28 15:34:34 -0500564
565GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
566 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
567 SkRect rect = GrTest::TestRect(random);
568
569 GrAAType aaType = GrAAType::kNone;
570 if (random->nextBool()) {
Chris Dalton6ce447a2019-06-23 18:07:38 -0600571 aaType = (numSamples > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
Michael Ludwig69858532018-11-28 15:34:34 -0500572 }
573 const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
574 : GrGetRandomStencil(random, context);
575
576 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
577 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
578 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
579 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
580 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
581
582 if (random->nextBool()) {
583 if (random->nextBool()) {
Robert Phillips438d9862019-11-14 12:46:05 -0500584 // Single local matrix
585 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500586 DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix),
587 GrQuad::MakeFromRect(rect, localMatrix), aaFlags};
Robert Phillipsfbf02142021-09-01 16:31:34 -0400588 return skgpu::v1::FillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500589 } else {
590 // Pass local rect directly
591 SkRect localRect = GrTest::TestRect(random);
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500592 DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix),
593 GrQuad(localRect), aaFlags};
Robert Phillipsfbf02142021-09-01 16:31:34 -0400594 return skgpu::v1::FillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500595 }
596 } else {
597 // The simplest constructor
Michael Ludwig6b45c5d2020-02-07 09:56:38 -0500598 DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(rect), aaFlags};
Robert Phillipsfbf02142021-09-01 16:31:34 -0400599 return skgpu::v1::FillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
Michael Ludwig69858532018-11-28 15:34:34 -0500600 }
601}
602
603#endif