blob: ef19367f61822e2f4662ca473b6de066ec0f33a9 [file] [log] [blame]
ethannicholas6536ae52016-05-02 12:16:49 -07001/*
2 * Copyright 2016 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
8#include "GrMSAAPathRenderer.h"
robertphillips976f5f02016-06-03 10:59:20 -07009#include "GrAuditTrail.h"
robertphillips976f5f02016-06-03 10:59:20 -070010#include "GrClip.h"
ethannicholas6536ae52016-05-02 12:16:49 -070011#include "GrDefaultGeoProcFactory.h"
csmartdalton02fa32c2016-08-19 13:29:27 -070012#include "GrFixedClip.h"
Brian Salomondad29232016-12-01 16:40:24 -050013#include "GrMesh.h"
Brian Salomon742e31d2016-12-07 17:06:19 -050014#include "GrOpFlushState.h"
ethannicholas6536ae52016-05-02 12:16:49 -070015#include "GrPathStencilSettings.h"
16#include "GrPathUtils.h"
Brian Salomon1cc3b152017-07-11 15:53:18 -040017#include "GrSimpleMeshDrawOpHelper.h"
Hal Canary95e3c052017-01-11 12:44:43 -050018#include "SkAutoMalloc.h"
ethannicholas6536ae52016-05-02 12:16:49 -070019#include "SkGeometry.h"
20#include "SkTraceEvent.h"
Brian Salomondad29232016-12-01 16:40:24 -050021#include "gl/GrGLVaryingHandler.h"
ethannicholas6536ae52016-05-02 12:16:49 -070022#include "glsl/GrGLSLFragmentShaderBuilder.h"
Brian Salomondad29232016-12-01 16:40:24 -050023#include "glsl/GrGLSLGeometryProcessor.h"
ethannicholas6536ae52016-05-02 12:16:49 -070024#include "glsl/GrGLSLProgramDataManager.h"
25#include "glsl/GrGLSLUtil.h"
Brian Salomondad29232016-12-01 16:40:24 -050026#include "glsl/GrGLSLVertexShaderBuilder.h"
Brian Salomon89527432016-12-16 09:52:16 -050027#include "ops/GrMeshDrawOp.h"
Brian Salomonbaaf4392017-06-15 09:59:23 -040028#include "ops/GrRectOpFactory.h"
ethannicholas6536ae52016-05-02 12:16:49 -070029
30static const float kTolerance = 0.5f;
31
32////////////////////////////////////////////////////////////////////////////////
33// Helpers for drawPath
34
bsalomon8acedde2016-06-24 10:42:16 -070035static inline bool single_pass_shape(const GrShape& shape) {
36 if (!shape.inverseFilled()) {
37 return shape.knownToBeConvex();
ethannicholas6536ae52016-05-02 12:16:49 -070038 }
39 return false;
40}
41
bsalomon8acedde2016-06-24 10:42:16 -070042GrPathRenderer::StencilSupport GrMSAAPathRenderer::onGetStencilSupport(const GrShape& shape) const {
43 if (single_pass_shape(shape)) {
ethannicholas6536ae52016-05-02 12:16:49 -070044 return GrPathRenderer::kNoRestriction_StencilSupport;
45 } else {
46 return GrPathRenderer::kStencilOnly_StencilSupport;
47 }
48}
49
50struct MSAALineVertices {
51 struct Vertex {
52 SkPoint fPosition;
53 SkColor fColor;
54 };
55 Vertex* vertices;
56 Vertex* nextVertex;
57#ifdef SK_DEBUG
58 Vertex* verticesEnd;
59#endif
60 uint16_t* indices;
61 uint16_t* nextIndex;
62};
63
64struct MSAAQuadVertices {
65 struct Vertex {
66 SkPoint fPosition;
67 SkPoint fUV;
68 SkColor fColor;
69 };
70 Vertex* vertices;
71 Vertex* nextVertex;
72#ifdef SK_DEBUG
73 Vertex* verticesEnd;
74#endif
75 uint16_t* indices;
76 uint16_t* nextIndex;
77};
78
79static inline void append_contour_edge_indices(uint16_t fanCenterIdx,
80 uint16_t edgeV0Idx,
81 MSAALineVertices& lines) {
82 *(lines.nextIndex++) = fanCenterIdx;
83 *(lines.nextIndex++) = edgeV0Idx;
84 *(lines.nextIndex++) = edgeV0Idx + 1;
85}
86
bungeman06ca8ec2016-06-09 08:01:03 -070087static inline void add_quad(MSAALineVertices& lines, MSAAQuadVertices& quads, const SkPoint pts[],
ethannicholas6536ae52016-05-02 12:16:49 -070088 SkColor color, bool indexed, uint16_t subpathLineIdxStart) {
89 SkASSERT(lines.nextVertex < lines.verticesEnd);
90 *lines.nextVertex = { pts[2], color };
91 if (indexed) {
92 int prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
93 if (prevIdx > subpathLineIdxStart) {
94 append_contour_edge_indices(subpathLineIdxStart, prevIdx, lines);
95 }
96 }
97 lines.nextVertex++;
98
99 SkASSERT(quads.nextVertex + 2 < quads.verticesEnd);
100 // the texture coordinates are drawn from the Loop-Blinn rendering algorithm
101 *(quads.nextVertex++) = { pts[0], SkPoint::Make(0.0, 0.0), color };
102 *(quads.nextVertex++) = { pts[1], SkPoint::Make(0.5, 0.0), color };
103 *(quads.nextVertex++) = { pts[2], SkPoint::Make(1.0, 1.0), color };
104 if (indexed) {
105 uint16_t offset = (uint16_t) (quads.nextVertex - quads.vertices) - 3;
106 *(quads.nextIndex++) = offset++;
107 *(quads.nextIndex++) = offset++;
108 *(quads.nextIndex++) = offset++;
109 }
110}
111
Brian Salomon1cc3b152017-07-11 15:53:18 -0400112namespace {
113
ethannicholas6536ae52016-05-02 12:16:49 -0700114class MSAAQuadProcessor : public GrGeometryProcessor {
115public:
116 static GrGeometryProcessor* Create(const SkMatrix& viewMatrix) {
117 return new MSAAQuadProcessor(viewMatrix);
118 }
119
Brian Salomond3b65972017-03-22 12:05:03 -0400120 ~MSAAQuadProcessor() override {}
ethannicholas6536ae52016-05-02 12:16:49 -0700121
122 const char* name() const override { return "MSAAQuadProcessor"; }
123
124 const Attribute* inPosition() const { return fInPosition; }
125 const Attribute* inUV() const { return fInUV; }
126 const Attribute* inColor() const { return fInColor; }
127 const SkMatrix& viewMatrix() const { return fViewMatrix; }
ethannicholas6536ae52016-05-02 12:16:49 -0700128
129 class GLSLProcessor : public GrGLSLGeometryProcessor {
130 public:
131 GLSLProcessor(const GrGeometryProcessor& qpr) {}
132
133 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
134 const MSAAQuadProcessor& qp = args.fGP.cast<MSAAQuadProcessor>();
135 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
136 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
137 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
138
139 // emit attributes
140 varyingHandler->emitAttributes(qp);
141 varyingHandler->addPassThroughAttribute(qp.inColor(), args.fOutputColor);
142
Brian Salomon1d816b92017-08-17 11:07:59 -0400143 GrGLSLVertToFrag uv(kVec2f_GrSLType);
ethannicholas6536ae52016-05-02 12:16:49 -0700144 varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision);
145 vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qp.inUV()->fName);
146
147 // Setup position
Brian Salomon7f235432017-08-16 09:41:48 -0400148 this->writeOutputPosition(vsBuilder, uniformHandler, gpArgs, qp.inPosition()->fName,
149 qp.viewMatrix(), &fViewMatrixUniform);
ethannicholas6536ae52016-05-02 12:16:49 -0700150
151 // emit transforms
bungeman06ca8ec2016-06-09 08:01:03 -0700152 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
bsalomona624bf32016-09-20 09:12:47 -0700153 qp.inPosition()->fName, SkMatrix::I(),
154 args.fFPCoordTransformHandler);
ethannicholas6536ae52016-05-02 12:16:49 -0700155
156 GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
bungeman06ca8ec2016-06-09 08:01:03 -0700157 fsBuilder->codeAppendf("if (%s.x * %s.x >= %s.y) discard;", uv.fsIn(), uv.fsIn(),
ethannicholas6536ae52016-05-02 12:16:49 -0700158 uv.fsIn());
Brian Salomon1d816b92017-08-17 11:07:59 -0400159 fsBuilder->codeAppendf("%s = float4(1.0);", args.fOutputCoverage);
ethannicholas6536ae52016-05-02 12:16:49 -0700160 }
161
162 static inline void GenKey(const GrGeometryProcessor& gp,
Brian Salomon94efbf52016-11-29 13:43:05 -0500163 const GrShaderCaps&,
ethannicholas6536ae52016-05-02 12:16:49 -0700164 GrProcessorKeyBuilder* b) {
165 const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
166 uint32_t key = 0;
167 key |= qp.viewMatrix().hasPerspective() ? 0x1 : 0x0;
168 key |= qp.viewMatrix().isIdentity() ? 0x2: 0x0;
169 b->add32(key);
170 }
171
bsalomona624bf32016-09-20 09:12:47 -0700172 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp,
173 FPCoordTransformIter&& transformIter) override {
ethannicholas6536ae52016-05-02 12:16:49 -0700174 const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
175 if (!qp.viewMatrix().isIdentity()) {
176 float viewMatrix[3 * 3];
177 GrGLSLGetMatrix<3>(viewMatrix, qp.viewMatrix());
178 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
179 }
bsalomona624bf32016-09-20 09:12:47 -0700180 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
ethannicholas6536ae52016-05-02 12:16:49 -0700181 }
182
ethannicholas6536ae52016-05-02 12:16:49 -0700183 private:
184 typedef GrGLSLGeometryProcessor INHERITED;
185
186 UniformHandle fViewMatrixUniform;
187 };
188
Brian Salomon94efbf52016-11-29 13:43:05 -0500189 virtual void getGLSLProcessorKey(const GrShaderCaps& caps,
ethannicholas6536ae52016-05-02 12:16:49 -0700190 GrProcessorKeyBuilder* b) const override {
191 GLSLProcessor::GenKey(*this, caps, b);
192 }
193
Brian Salomon94efbf52016-11-29 13:43:05 -0500194 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
ethannicholas6536ae52016-05-02 12:16:49 -0700195 return new GLSLProcessor(*this);
196 }
197
198private:
199 MSAAQuadProcessor(const SkMatrix& viewMatrix)
200 : fViewMatrix(viewMatrix) {
201 this->initClassID<MSAAQuadProcessor>();
bsalomon6cb807b2016-08-17 11:33:39 -0700202 fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
203 kHigh_GrSLPrecision);
204 fInUV = &this->addVertexAttrib("inUV", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision);
205 fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
ethannicholas6536ae52016-05-02 12:16:49 -0700206 this->setSampleShading(1.0f);
207 }
208
209 const Attribute* fInPosition;
210 const Attribute* fInUV;
211 const Attribute* fInColor;
212 SkMatrix fViewMatrix;
bungeman06ca8ec2016-06-09 08:01:03 -0700213
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400214 GR_DECLARE_GEOMETRY_PROCESSOR_TEST
ethannicholas6536ae52016-05-02 12:16:49 -0700215
216 typedef GrGeometryProcessor INHERITED;
217};
218
Brian Salomon1cc3b152017-07-11 15:53:18 -0400219class MSAAPathOp final : public GrMeshDrawOp {
220private:
221 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
222
ethannicholas6536ae52016-05-02 12:16:49 -0700223public:
Brian Salomon25a88092016-12-01 09:36:50 -0500224 DEFINE_OP_CLASS_ID
Brian Salomon1cc3b152017-07-11 15:53:18 -0400225 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkPath& path, GrAAType aaType,
226 const SkMatrix& viewMatrix, const SkRect& devBounds,
227 const GrUserStencilSettings* stencilSettings) {
bsalomon50c56a32016-06-30 12:05:32 -0700228 int contourCount;
Brian Salomon780dad12016-12-15 18:08:40 -0500229 int maxLineVertices;
230 int maxQuadVertices;
Brian Salomon32ebaba2017-03-30 10:22:28 -0400231 ComputeWorstCasePointCount(path, viewMatrix, &contourCount, &maxLineVertices,
232 &maxQuadVertices);
Brian Salomon780dad12016-12-15 18:08:40 -0500233 bool isIndexed = contourCount > 1;
234 if (isIndexed &&
235 (maxLineVertices > kMaxIndexedVertexCnt || maxQuadVertices > kMaxIndexedVertexCnt)) {
236 return nullptr;
237 }
238
Brian Salomon1cc3b152017-07-11 15:53:18 -0400239 return Helper::FactoryHelper<MSAAPathOp>(std::move(paint), path, aaType, viewMatrix,
240 devBounds, maxLineVertices, maxQuadVertices,
241 isIndexed, stencilSettings);
ethannicholas6536ae52016-05-02 12:16:49 -0700242 }
243
Brian Salomon780dad12016-12-15 18:08:40 -0500244 const char* name() const override { return "MSAAPathOp"; }
ethannicholas6536ae52016-05-02 12:16:49 -0700245
Brian Salomon7c3e7182016-12-01 09:35:30 -0500246 SkString dumpInfo() const override {
247 SkString string;
248 string.appendf("Indexed: %d\n", fIsIndexed);
249 for (const auto& path : fPaths) {
250 string.appendf("Color: 0x%08x\n", path.fColor);
251 }
Brian Salomon1cc3b152017-07-11 15:53:18 -0400252 string += fHelper.dumpInfo();
253 string += INHERITED::dumpInfo();
Brian Salomon7c3e7182016-12-01 09:35:30 -0500254 return string;
255 }
256
Brian Salomon1cc3b152017-07-11 15:53:18 -0400257 MSAAPathOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkPath& path,
258 GrAAType aaType, const SkMatrix& viewMatrix, const SkRect& devBounds,
259 int maxLineVertices, int maxQuadVertices, bool isIndexed,
260 const GrUserStencilSettings* stencilSettings)
Brian Salomon780dad12016-12-15 18:08:40 -0500261 : INHERITED(ClassID())
Brian Salomon1cc3b152017-07-11 15:53:18 -0400262 , fHelper(helperArgs, aaType, stencilSettings)
Brian Salomon780dad12016-12-15 18:08:40 -0500263 , fViewMatrix(viewMatrix)
264 , fMaxLineVertices(maxLineVertices)
265 , fMaxQuadVertices(maxQuadVertices)
266 , fIsIndexed(isIndexed) {
267 fPaths.emplace_back(PathInfo{color, path});
268 this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo);
ethannicholas6536ae52016-05-02 12:16:49 -0700269 }
270
Brian Salomon1cc3b152017-07-11 15:53:18 -0400271 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
272
273 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
274 return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone,
275 &fPaths.front().fColor);
Brian Salomon92aee3d2016-12-21 09:20:25 -0500276 }
277
Brian Salomon1cc3b152017-07-11 15:53:18 -0400278private:
Brian Salomon32ebaba2017-03-30 10:22:28 -0400279 static void ComputeWorstCasePointCount(const SkPath& path, const SkMatrix& m, int* subpaths,
Brian Salomon780dad12016-12-15 18:08:40 -0500280 int* outLinePointCount, int* outQuadPointCount) {
Brian Salomon32ebaba2017-03-30 10:22:28 -0400281 SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m, path.getBounds());
ethannicholas6536ae52016-05-02 12:16:49 -0700282 int linePointCount = 0;
283 int quadPointCount = 0;
284 *subpaths = 1;
285
286 bool first = true;
287
bsalomon8eb43e52016-09-21 07:47:34 -0700288 SkPath::Iter iter(path, true);
ethannicholas6536ae52016-05-02 12:16:49 -0700289 SkPath::Verb verb;
290
291 SkPoint pts[4];
292 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
293 switch (verb) {
294 case SkPath::kLine_Verb:
295 linePointCount += 1;
296 break;
297 case SkPath::kConic_Verb: {
298 SkScalar weight = iter.conicWeight();
299 SkAutoConicToQuads converter;
Brian Salomon32ebaba2017-03-30 10:22:28 -0400300 converter.computeQuads(pts, weight, tolerance);
ethannicholas6536ae52016-05-02 12:16:49 -0700301 int quadPts = converter.countQuads();
302 linePointCount += quadPts;
303 quadPointCount += 3 * quadPts;
304 }
305 case SkPath::kQuad_Verb:
306 linePointCount += 1;
307 quadPointCount += 3;
308 break;
309 case SkPath::kCubic_Verb: {
310 SkSTArray<15, SkPoint, true> quadPts;
Brian Salomon32ebaba2017-03-30 10:22:28 -0400311 GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts);
ethannicholas6536ae52016-05-02 12:16:49 -0700312 int count = quadPts.count();
313 linePointCount += count / 3;
314 quadPointCount += count;
315 break;
316 }
317 case SkPath::kMove_Verb:
318 linePointCount += 1;
319 if (!first) {
320 ++(*subpaths);
321 }
322 break;
323 default:
324 break;
325 }
326 first = false;
327 }
328 *outLinePointCount = linePointCount;
329 *outQuadPointCount = quadPointCount;
330 }
331
Brian Salomon91326c32017-08-09 16:02:19 -0400332 void onPrepareDraws(Target* target) override {
ethannicholas6536ae52016-05-02 12:16:49 -0700333 if (fMaxLineVertices == 0) {
334 SkASSERT(fMaxQuadVertices == 0);
335 return;
336 }
337
Chris Dalton3809bab2017-06-13 10:55:06 -0600338 GrPrimitiveType primitiveType = fIsIndexed ? GrPrimitiveType::kTriangles
339 : GrPrimitiveType::kTriangleFan;
ethannicholas6536ae52016-05-02 12:16:49 -0700340
341 // allocate vertex / index buffers
342 const GrBuffer* lineVertexBuffer;
343 int firstLineVertex;
344 MSAALineVertices lines;
Chris Dalton1d616352017-05-31 12:51:23 -0600345 int lineVertexStride = sizeof(MSAALineVertices::Vertex);
bungeman06ca8ec2016-06-09 08:01:03 -0700346 lines.vertices = (MSAALineVertices::Vertex*) target->makeVertexSpace(lineVertexStride,
ethannicholas6536ae52016-05-02 12:16:49 -0700347 fMaxLineVertices,
bungeman06ca8ec2016-06-09 08:01:03 -0700348 &lineVertexBuffer,
ethannicholas6536ae52016-05-02 12:16:49 -0700349 &firstLineVertex);
350 if (!lines.vertices) {
351 SkDebugf("Could not allocate vertices\n");
352 return;
353 }
354 lines.nextVertex = lines.vertices;
355 SkDEBUGCODE(lines.verticesEnd = lines.vertices + fMaxLineVertices;)
356
357 MSAAQuadVertices quads;
Chris Dalton1d616352017-05-31 12:51:23 -0600358 int quadVertexStride = sizeof(MSAAQuadVertices::Vertex);
Hal Canary95e3c052017-01-11 12:44:43 -0500359 SkAutoMalloc quadVertexPtr(fMaxQuadVertices * quadVertexStride);
ethannicholas6536ae52016-05-02 12:16:49 -0700360 quads.vertices = (MSAAQuadVertices::Vertex*) quadVertexPtr.get();
361 quads.nextVertex = quads.vertices;
362 SkDEBUGCODE(quads.verticesEnd = quads.vertices + fMaxQuadVertices;)
363
364 const GrBuffer* lineIndexBuffer = nullptr;
365 int firstLineIndex;
366 if (fIsIndexed) {
Brian Salomon780dad12016-12-15 18:08:40 -0500367 lines.indices =
368 target->makeIndexSpace(3 * fMaxLineVertices, &lineIndexBuffer, &firstLineIndex);
ethannicholas6536ae52016-05-02 12:16:49 -0700369 if (!lines.indices) {
370 SkDebugf("Could not allocate indices\n");
371 return;
372 }
373 lines.nextIndex = lines.indices;
374 } else {
375 lines.indices = nullptr;
376 lines.nextIndex = nullptr;
377 }
378
379 SkAutoFree quadIndexPtr;
380 if (fIsIndexed) {
Brian Salomon780dad12016-12-15 18:08:40 -0500381 quads.indices = (uint16_t*)sk_malloc_throw(3 * fMaxQuadVertices * sizeof(uint16_t));
Hal Canary95e3c052017-01-11 12:44:43 -0500382 quadIndexPtr.reset(quads.indices);
ethannicholas6536ae52016-05-02 12:16:49 -0700383 quads.nextIndex = quads.indices;
384 } else {
385 quads.indices = nullptr;
386 quads.nextIndex = nullptr;
387 }
ethannicholas6536ae52016-05-02 12:16:49 -0700388 // fill buffers
bsalomon50c56a32016-06-30 12:05:32 -0700389 for (int i = 0; i < fPaths.count(); i++) {
390 const PathInfo& pathInfo = fPaths[i];
ethannicholas6536ae52016-05-02 12:16:49 -0700391 if (!this->createGeom(lines,
392 quads,
bsalomon50c56a32016-06-30 12:05:32 -0700393 pathInfo.fPath,
ethannicholas6536ae52016-05-02 12:16:49 -0700394 fViewMatrix,
bsalomon50c56a32016-06-30 12:05:32 -0700395 pathInfo.fColor,
ethannicholas6536ae52016-05-02 12:16:49 -0700396 fIsIndexed)) {
397 return;
398 }
399 }
400 int lineVertexOffset = (int) (lines.nextVertex - lines.vertices);
401 int lineIndexOffset = (int) (lines.nextIndex - lines.indices);
Brian Salomon780dad12016-12-15 18:08:40 -0500402 SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= 3 * fMaxLineVertices);
ethannicholas6536ae52016-05-02 12:16:49 -0700403 int quadVertexOffset = (int) (quads.nextVertex - quads.vertices);
404 int quadIndexOffset = (int) (quads.nextIndex - quads.indices);
Brian Salomon780dad12016-12-15 18:08:40 -0500405 SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= 3 * fMaxQuadVertices);
ethannicholas6536ae52016-05-02 12:16:49 -0700406
Brian Salomon1cc3b152017-07-11 15:53:18 -0400407 const GrPipeline* pipeline = fHelper.makePipeline(target);
408
ethannicholas6536ae52016-05-02 12:16:49 -0700409 if (lineVertexOffset) {
bungeman06ca8ec2016-06-09 08:01:03 -0700410 sk_sp<GrGeometryProcessor> lineGP;
ethannicholas6536ae52016-05-02 12:16:49 -0700411 {
412 using namespace GrDefaultGeoProcFactory;
Brian Salomon3de0aee2017-01-29 09:34:17 -0500413 lineGP = GrDefaultGeoProcFactory::Make(Color(Color::kPremulGrColorAttribute_Type),
Brian Salomon8c852be2017-01-04 10:44:42 -0500414 Coverage::kSolid_Type,
bungeman06ca8ec2016-06-09 08:01:03 -0700415 LocalCoords(LocalCoords::kUnused_Type),
416 fViewMatrix);
ethannicholas6536ae52016-05-02 12:16:49 -0700417 }
418 SkASSERT(lineVertexStride == lineGP->getVertexStride());
419
Chris Daltonbca46e22017-05-15 11:03:26 -0600420 GrMesh lineMeshes(primitiveType);
Chris Dalton114a3c02017-05-26 15:17:19 -0600421 if (!fIsIndexed) {
Chris Dalton1d616352017-05-31 12:51:23 -0600422 lineMeshes.setNonIndexedNonInstanced(lineVertexOffset);
Chris Dalton114a3c02017-05-26 15:17:19 -0600423 } else {
424 lineMeshes.setIndexed(lineIndexBuffer, lineIndexOffset, firstLineIndex,
425 0, lineVertexOffset - 1);
ethannicholas6536ae52016-05-02 12:16:49 -0700426 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600427 lineMeshes.setVertexData(lineVertexBuffer, firstLineVertex);
Chris Daltonff926502017-05-03 14:36:54 -0400428
Brian Salomon2a55c8e2017-05-09 09:57:19 -0400429 // We can get line vertices from path moveTos with no actual segments and thus no index
430 // count. We assert that indexed draws contain a positive index count, so bail here in
431 // that case.
432 if (!fIsIndexed || lineIndexOffset) {
Brian Salomon1cc3b152017-07-11 15:53:18 -0400433 target->draw(lineGP.get(), pipeline, lineMeshes);
Brian Salomon2a55c8e2017-05-09 09:57:19 -0400434 }
ethannicholas6536ae52016-05-02 12:16:49 -0700435 }
436
437 if (quadVertexOffset) {
Hal Canary144caf52016-11-07 17:57:18 -0500438 sk_sp<const GrGeometryProcessor> quadGP(MSAAQuadProcessor::Create(fViewMatrix));
ethannicholas6536ae52016-05-02 12:16:49 -0700439 SkASSERT(quadVertexStride == quadGP->getVertexStride());
440
441 const GrBuffer* quadVertexBuffer;
442 int firstQuadVertex;
bungeman06ca8ec2016-06-09 08:01:03 -0700443 MSAAQuadVertices::Vertex* quadVertices = (MSAAQuadVertices::Vertex*)
ethannicholas6536ae52016-05-02 12:16:49 -0700444 target->makeVertexSpace(quadVertexStride, quadVertexOffset, &quadVertexBuffer,
445 &firstQuadVertex);
446 memcpy(quadVertices, quads.vertices, quadVertexStride * quadVertexOffset);
Chris Dalton3809bab2017-06-13 10:55:06 -0600447 GrMesh quadMeshes(GrPrimitiveType::kTriangles);
Chris Dalton114a3c02017-05-26 15:17:19 -0600448 if (!fIsIndexed) {
Chris Dalton1d616352017-05-31 12:51:23 -0600449 quadMeshes.setNonIndexedNonInstanced(quadVertexOffset);
Chris Dalton114a3c02017-05-26 15:17:19 -0600450 } else {
ethannicholas6536ae52016-05-02 12:16:49 -0700451 const GrBuffer* quadIndexBuffer;
Chris Daltonbca46e22017-05-15 11:03:26 -0600452 int firstQuadIndex;
bungeman06ca8ec2016-06-09 08:01:03 -0700453 uint16_t* quadIndices = (uint16_t*) target->makeIndexSpace(quadIndexOffset,
454 &quadIndexBuffer,
Chris Daltonbca46e22017-05-15 11:03:26 -0600455 &firstQuadIndex);
ethannicholas6536ae52016-05-02 12:16:49 -0700456 memcpy(quadIndices, quads.indices, sizeof(uint16_t) * quadIndexOffset);
Chris Dalton114a3c02017-05-26 15:17:19 -0600457 quadMeshes.setIndexed(quadIndexBuffer, quadIndexOffset, firstQuadIndex,
458 0, quadVertexOffset - 1);
ethannicholas6536ae52016-05-02 12:16:49 -0700459 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600460 quadMeshes.setVertexData(quadVertexBuffer, firstQuadVertex);
Brian Salomon1cc3b152017-07-11 15:53:18 -0400461 target->draw(quadGP.get(), pipeline, quadMeshes);
ethannicholas6536ae52016-05-02 12:16:49 -0700462 }
463 }
464
Brian Salomon25a88092016-12-01 09:36:50 -0500465 bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
Brian Salomon780dad12016-12-15 18:08:40 -0500466 MSAAPathOp* that = t->cast<MSAAPathOp>();
Brian Salomon1cc3b152017-07-11 15:53:18 -0400467 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
ethannicholas6536ae52016-05-02 12:16:49 -0700468 return false;
469 }
470
Jim Van Verth9d01fbc2017-02-22 14:50:52 -0500471 if (this->bounds().intersects(that->bounds())) {
472 return false;
473 }
474
ethannicholas6536ae52016-05-02 12:16:49 -0700475 if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
476 return false;
477 }
478
Brian Salomon780dad12016-12-15 18:08:40 -0500479 // If we grow to include 2+ paths we will be indexed.
480 if (((fMaxLineVertices + that->fMaxLineVertices) > kMaxIndexedVertexCnt) ||
481 ((fMaxQuadVertices + that->fMaxQuadVertices) > kMaxIndexedVertexCnt)) {
ethannicholas6536ae52016-05-02 12:16:49 -0700482 return false;
483 }
484
bsalomon50c56a32016-06-30 12:05:32 -0700485 fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
bsalomon88cf17d2016-07-08 06:40:56 -0700486 this->joinBounds(*that);
ethannicholas6536ae52016-05-02 12:16:49 -0700487 fIsIndexed = true;
488 fMaxLineVertices += that->fMaxLineVertices;
489 fMaxQuadVertices += that->fMaxQuadVertices;
ethannicholas6536ae52016-05-02 12:16:49 -0700490 return true;
491 }
492
493 bool createGeom(MSAALineVertices& lines,
494 MSAAQuadVertices& quads,
495 const SkPath& path,
ethannicholas6536ae52016-05-02 12:16:49 -0700496 const SkMatrix& m,
497 SkColor color,
498 bool isIndexed) const {
499 {
Brian Salomon32ebaba2017-03-30 10:22:28 -0400500 const SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m,
501 path.getBounds());
ethannicholas6536ae52016-05-02 12:16:49 -0700502 uint16_t subpathIdxStart = (uint16_t) (lines.nextVertex - lines.vertices);
503
504 SkPoint pts[4];
505
506 bool first = true;
bsalomon8eb43e52016-09-21 07:47:34 -0700507 SkPath::Iter iter(path, true);
ethannicholas6536ae52016-05-02 12:16:49 -0700508
509 bool done = false;
510 while (!done) {
511 SkPath::Verb verb = iter.next(pts);
512 switch (verb) {
513 case SkPath::kMove_Verb:
514 if (!first) {
515 uint16_t currIdx = (uint16_t) (lines.nextVertex - lines.vertices);
516 subpathIdxStart = currIdx;
517 }
518 SkASSERT(lines.nextVertex < lines.verticesEnd);
519 *(lines.nextVertex++) = { pts[0], color };
520 break;
521 case SkPath::kLine_Verb:
522 if (isIndexed) {
523 uint16_t prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
524 if (prevIdx > subpathIdxStart) {
525 append_contour_edge_indices(subpathIdxStart, prevIdx, lines);
526 }
527 }
528 SkASSERT(lines.nextVertex < lines.verticesEnd);
529 *(lines.nextVertex++) = { pts[1], color };
530 break;
531 case SkPath::kConic_Verb: {
532 SkScalar weight = iter.conicWeight();
533 SkAutoConicToQuads converter;
Brian Salomon32ebaba2017-03-30 10:22:28 -0400534 const SkPoint* quadPts = converter.computeQuads(pts, weight, tolerance);
ethannicholas6536ae52016-05-02 12:16:49 -0700535 for (int i = 0; i < converter.countQuads(); ++i) {
bungeman06ca8ec2016-06-09 08:01:03 -0700536 add_quad(lines, quads, quadPts + i * 2, color, isIndexed,
ethannicholas6536ae52016-05-02 12:16:49 -0700537 subpathIdxStart);
538 }
539 break;
540 }
541 case SkPath::kQuad_Verb: {
542 add_quad(lines, quads, pts, color, isIndexed, subpathIdxStart);
bungeman06ca8ec2016-06-09 08:01:03 -0700543 break;
ethannicholas6536ae52016-05-02 12:16:49 -0700544 }
545 case SkPath::kCubic_Verb: {
546 SkSTArray<15, SkPoint, true> quadPts;
Brian Salomon32ebaba2017-03-30 10:22:28 -0400547 GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts);
ethannicholas6536ae52016-05-02 12:16:49 -0700548 int count = quadPts.count();
549 for (int i = 0; i < count; i += 3) {
550 add_quad(lines, quads, &quadPts[i], color, isIndexed, subpathIdxStart);
551 }
552 break;
553 }
554 case SkPath::kClose_Verb:
555 break;
556 case SkPath::kDone_Verb:
557 done = true;
558 }
559 first = false;
560 }
561 }
562 return true;
563 }
564
Brian Salomon780dad12016-12-15 18:08:40 -0500565 // Lines and quads may render with an index buffer. However, we don't have any support for
566 // overflowing the max index.
567 static constexpr int kMaxIndexedVertexCnt = SK_MaxU16 / 3;
bsalomon50c56a32016-06-30 12:05:32 -0700568 struct PathInfo {
569 GrColor fColor;
570 SkPath fPath;
571 };
572
Brian Salomon1cc3b152017-07-11 15:53:18 -0400573 Helper fHelper;
bsalomon50c56a32016-06-30 12:05:32 -0700574 SkSTArray<1, PathInfo, true> fPaths;
ethannicholas6536ae52016-05-02 12:16:49 -0700575 SkMatrix fViewMatrix;
576 int fMaxLineVertices;
577 int fMaxQuadVertices;
ethannicholas6536ae52016-05-02 12:16:49 -0700578 bool fIsIndexed;
579
Brian Salomon1cc3b152017-07-11 15:53:18 -0400580 typedef GrMeshDrawOp INHERITED;
ethannicholas6536ae52016-05-02 12:16:49 -0700581};
582
Brian Salomon1cc3b152017-07-11 15:53:18 -0400583} // anonymous namespace
584
Brian Osman11052242016-10-27 14:47:55 -0400585bool GrMSAAPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext,
Brian Salomon82f44312017-01-11 13:42:54 -0500586 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500587 GrAAType aaType,
robertphillipsd2b6d642016-07-21 08:55:08 -0700588 const GrUserStencilSettings& userStencilSettings,
cdalton862cff32016-05-12 15:09:48 -0700589 const GrClip& clip,
ethannicholas6536ae52016-05-02 12:16:49 -0700590 const SkMatrix& viewMatrix,
bsalomon8acedde2016-06-24 10:42:16 -0700591 const GrShape& shape,
ethannicholas6536ae52016-05-02 12:16:49 -0700592 bool stencilOnly) {
bsalomon8acedde2016-06-24 10:42:16 -0700593 SkASSERT(shape.style().isSimpleFill());
594 SkPath path;
595 shape.asPath(&path);
596
Brian Salomon82f44312017-01-11 13:42:54 -0500597 const GrUserStencilSettings* passes[2] = {nullptr, nullptr};
cdalton93a379b2016-05-11 13:58:08 -0700598 bool reverse = false;
ethannicholas6536ae52016-05-02 12:16:49 -0700599
bsalomon8acedde2016-06-24 10:42:16 -0700600 if (single_pass_shape(shape)) {
ethannicholas6536ae52016-05-02 12:16:49 -0700601 if (stencilOnly) {
602 passes[0] = &gDirectToStencil;
603 } else {
robertphillipsd2b6d642016-07-21 08:55:08 -0700604 passes[0] = &userStencilSettings;
ethannicholas6536ae52016-05-02 12:16:49 -0700605 }
ethannicholas6536ae52016-05-02 12:16:49 -0700606 } else {
607 switch (path.getFillType()) {
608 case SkPath::kInverseEvenOdd_FillType:
609 reverse = true;
610 // fallthrough
611 case SkPath::kEvenOdd_FillType:
612 passes[0] = &gEOStencilPass;
Brian Salomon82f44312017-01-11 13:42:54 -0500613 if (!stencilOnly) {
614 passes[1] = reverse ? &gInvEOColorPass : &gEOColorPass;
ethannicholas6536ae52016-05-02 12:16:49 -0700615 }
ethannicholas6536ae52016-05-02 12:16:49 -0700616 break;
617
618 case SkPath::kInverseWinding_FillType:
619 reverse = true;
620 // fallthrough
621 case SkPath::kWinding_FillType:
Brian Salomon15b25092017-05-08 11:10:53 -0400622 passes[0] = &gWindStencilPass;
Brian Salomon82f44312017-01-11 13:42:54 -0500623 if (!stencilOnly) {
624 passes[1] = reverse ? &gInvWindColorPass : &gWindColorPass;
ethannicholas6536ae52016-05-02 12:16:49 -0700625 }
626 break;
627 default:
628 SkDEBUGFAIL("Unknown path fFill!");
629 return false;
630 }
631 }
632
633 SkRect devBounds;
Brian Osman11052242016-10-27 14:47:55 -0400634 GetPathDevBounds(path, renderTargetContext->width(), renderTargetContext->height(), viewMatrix,
635 &devBounds);
ethannicholas6536ae52016-05-02 12:16:49 -0700636
Brian Salomond4652ca2017-01-13 12:11:36 -0500637 SkASSERT(passes[0]);
638 { // First pass
Brian Salomond4652ca2017-01-13 12:11:36 -0500639 bool firstPassIsStencil = stencilOnly || passes[1];
640 // If we have a cover pass then we ignore the paint in the first pass and apply it in the
641 // second.
Brian Salomonb74ef032017-08-10 12:46:01 -0400642 std::unique_ptr<GrDrawOp> op;
Brian Salomond4652ca2017-01-13 12:11:36 -0500643 if (firstPassIsStencil) {
Brian Salomonb74ef032017-08-10 12:46:01 -0400644 GrPaint stencilPaint;
645 stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
646 op = MSAAPathOp::Make(std::move(stencilPaint), path, aaType, viewMatrix, devBounds,
647 passes[0]);
648 } else {
649 op = MSAAPathOp::Make(std::move(paint), path, aaType, viewMatrix, devBounds, passes[0]);
Brian Salomond4652ca2017-01-13 12:11:36 -0500650 }
Brian Salomon1cc3b152017-07-11 15:53:18 -0400651 if (!op) {
652 return false;
653 }
654 renderTargetContext->addDrawOp(clip, std::move(op));
Brian Salomon82f44312017-01-11 13:42:54 -0500655 }
robertphillips8e375302016-07-11 10:43:58 -0700656
Brian Salomon82f44312017-01-11 13:42:54 -0500657 if (passes[1]) {
658 SkRect bounds;
659 SkMatrix localMatrix = SkMatrix::I();
660 if (reverse) {
661 // draw over the dev bounds (which will be the whole dst surface for inv fill).
662 bounds = devBounds;
663 SkMatrix vmi;
664 // mapRect through persp matrix may not be correct
665 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
666 vmi.mapRect(&bounds);
ethannicholas6536ae52016-05-02 12:16:49 -0700667 } else {
Brian Salomon82f44312017-01-11 13:42:54 -0500668 if (!viewMatrix.invert(&localMatrix)) {
669 return false;
670 }
ethannicholas6536ae52016-05-02 12:16:49 -0700671 }
robertphillips976f5f02016-06-03 10:59:20 -0700672 } else {
Brian Salomon82f44312017-01-11 13:42:54 -0500673 bounds = path.getBounds();
ethannicholas6536ae52016-05-02 12:16:49 -0700674 }
Brian Salomon82f44312017-01-11 13:42:54 -0500675 const SkMatrix& viewM =
676 (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix;
Brian Salomonac70f842017-05-08 10:43:33 -0400677 renderTargetContext->addDrawOp(
678 clip,
Brian Salomonbaaf4392017-06-15 09:59:23 -0400679 GrRectOpFactory::MakeNonAAFillWithLocalMatrix(std::move(paint), viewM, localMatrix,
680 bounds, aaType, passes[1]));
ethannicholas6536ae52016-05-02 12:16:49 -0700681 }
682 return true;
683}
684
685bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
Eric Karl5c779752017-05-08 12:02:07 -0700686 // If we aren't a single_pass_shape, we require stencil buffers.
687 if (!single_pass_shape(*args.fShape) && args.fCaps->avoidStencilBuffers()) {
688 return false;
689 }
bsalomonee432412016-06-27 07:18:18 -0700690 // This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are
691 // handled by passing on the original shape and letting the caller compute the stroked shape
692 // which will have a fill style.
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500693 return args.fShape->style().isSimpleFill() && (GrAAType::kCoverage != args.fAAType);
ethannicholas6536ae52016-05-02 12:16:49 -0700694}
695
696bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -0400697 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
robertphillips976f5f02016-06-03 10:59:20 -0700698 "GrMSAAPathRenderer::onDrawPath");
bsalomon8acedde2016-06-24 10:42:16 -0700699 SkTLazy<GrShape> tmpShape;
700 const GrShape* shape = args.fShape;
701 if (shape->style().applies()) {
bsalomon6663acf2016-05-10 09:14:17 -0700702 SkScalar styleScale = GrStyle::MatrixToScaleFactor(*args.fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700703 tmpShape.init(args.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale));
704 shape = tmpShape.get();
ethannicholas6536ae52016-05-02 12:16:49 -0700705 }
Brian Osman11052242016-10-27 14:47:55 -0400706 return this->internalDrawPath(args.fRenderTargetContext,
Brian Salomon82f44312017-01-11 13:42:54 -0500707 std::move(args.fPaint),
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500708 args.fAAType,
robertphillipsd2b6d642016-07-21 08:55:08 -0700709 *args.fUserStencilSettings,
cdalton862cff32016-05-12 15:09:48 -0700710 *args.fClip,
ethannicholas6536ae52016-05-02 12:16:49 -0700711 *args.fViewMatrix,
bsalomon8acedde2016-06-24 10:42:16 -0700712 *shape,
ethannicholas6536ae52016-05-02 12:16:49 -0700713 false);
714}
715
716void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -0400717 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
robertphillips976f5f02016-06-03 10:59:20 -0700718 "GrMSAAPathRenderer::onStencilPath");
bsalomon8acedde2016-06-24 10:42:16 -0700719 SkASSERT(args.fShape->style().isSimpleFill());
720 SkASSERT(!args.fShape->mayBeInverseFilledAfterStyling());
robertphillips976f5f02016-06-03 10:59:20 -0700721
722 GrPaint paint;
Brian Salomona1633922017-01-09 11:46:10 -0500723 paint.setXPFactory(GrDisableColorXPFactory::Get());
robertphillips976f5f02016-06-03 10:59:20 -0700724
Brian Salomon82f44312017-01-11 13:42:54 -0500725 this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500726 GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix,
727 *args.fShape, true);
ethannicholas6536ae52016-05-02 12:16:49 -0700728}
729
730///////////////////////////////////////////////////////////////////////////////////////////////////