blob: 05a23a1e0581db2a2fb6212bd6db65dccb1207b3 [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"
9
robertphillips976f5f02016-06-03 10:59:20 -070010#include "GrAuditTrail.h"
ethannicholas6536ae52016-05-02 12:16:49 -070011#include "GrBatchFlushState.h"
robertphillips976f5f02016-06-03 10:59:20 -070012#include "GrClip.h"
ethannicholas6536ae52016-05-02 12:16:49 -070013#include "GrDefaultGeoProcFactory.h"
14#include "GrPathStencilSettings.h"
15#include "GrPathUtils.h"
bsalomonbb243832016-07-22 07:10:19 -070016#include "GrPipelineBuilder.h"
ethannicholas6536ae52016-05-02 12:16:49 -070017#include "GrMesh.h"
18#include "SkGeometry.h"
19#include "SkTraceEvent.h"
20#include "glsl/GrGLSLGeometryProcessor.h"
21#include "glsl/GrGLSLFragmentShaderBuilder.h"
22#include "glsl/GrGLSLVertexShaderBuilder.h"
23#include "glsl/GrGLSLProgramDataManager.h"
24#include "glsl/GrGLSLUtil.h"
25#include "gl/GrGLVaryingHandler.h"
26#include "batches/GrRectBatchFactory.h"
27#include "batches/GrVertexBatch.h"
28
29static const float kTolerance = 0.5f;
30
31////////////////////////////////////////////////////////////////////////////////
32// Helpers for drawPath
33
bsalomon8acedde2016-06-24 10:42:16 -070034static inline bool single_pass_shape(const GrShape& shape) {
35 if (!shape.inverseFilled()) {
36 return shape.knownToBeConvex();
ethannicholas6536ae52016-05-02 12:16:49 -070037 }
38 return false;
39}
40
bsalomon8acedde2016-06-24 10:42:16 -070041GrPathRenderer::StencilSupport GrMSAAPathRenderer::onGetStencilSupport(const GrShape& shape) const {
42 if (single_pass_shape(shape)) {
ethannicholas6536ae52016-05-02 12:16:49 -070043 return GrPathRenderer::kNoRestriction_StencilSupport;
44 } else {
45 return GrPathRenderer::kStencilOnly_StencilSupport;
46 }
47}
48
49struct MSAALineVertices {
50 struct Vertex {
51 SkPoint fPosition;
52 SkColor fColor;
53 };
54 Vertex* vertices;
55 Vertex* nextVertex;
56#ifdef SK_DEBUG
57 Vertex* verticesEnd;
58#endif
59 uint16_t* indices;
60 uint16_t* nextIndex;
61};
62
63struct MSAAQuadVertices {
64 struct Vertex {
65 SkPoint fPosition;
66 SkPoint fUV;
67 SkColor fColor;
68 };
69 Vertex* vertices;
70 Vertex* nextVertex;
71#ifdef SK_DEBUG
72 Vertex* verticesEnd;
73#endif
74 uint16_t* indices;
75 uint16_t* nextIndex;
76};
77
78static inline void append_contour_edge_indices(uint16_t fanCenterIdx,
79 uint16_t edgeV0Idx,
80 MSAALineVertices& lines) {
81 *(lines.nextIndex++) = fanCenterIdx;
82 *(lines.nextIndex++) = edgeV0Idx;
83 *(lines.nextIndex++) = edgeV0Idx + 1;
84}
85
bungeman06ca8ec2016-06-09 08:01:03 -070086static inline void add_quad(MSAALineVertices& lines, MSAAQuadVertices& quads, const SkPoint pts[],
ethannicholas6536ae52016-05-02 12:16:49 -070087 SkColor color, bool indexed, uint16_t subpathLineIdxStart) {
88 SkASSERT(lines.nextVertex < lines.verticesEnd);
89 *lines.nextVertex = { pts[2], color };
90 if (indexed) {
91 int prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
92 if (prevIdx > subpathLineIdxStart) {
93 append_contour_edge_indices(subpathLineIdxStart, prevIdx, lines);
94 }
95 }
96 lines.nextVertex++;
97
98 SkASSERT(quads.nextVertex + 2 < quads.verticesEnd);
99 // the texture coordinates are drawn from the Loop-Blinn rendering algorithm
100 *(quads.nextVertex++) = { pts[0], SkPoint::Make(0.0, 0.0), color };
101 *(quads.nextVertex++) = { pts[1], SkPoint::Make(0.5, 0.0), color };
102 *(quads.nextVertex++) = { pts[2], SkPoint::Make(1.0, 1.0), color };
103 if (indexed) {
104 uint16_t offset = (uint16_t) (quads.nextVertex - quads.vertices) - 3;
105 *(quads.nextIndex++) = offset++;
106 *(quads.nextIndex++) = offset++;
107 *(quads.nextIndex++) = offset++;
108 }
109}
110
111class MSAAQuadProcessor : public GrGeometryProcessor {
112public:
113 static GrGeometryProcessor* Create(const SkMatrix& viewMatrix) {
114 return new MSAAQuadProcessor(viewMatrix);
115 }
116
117 virtual ~MSAAQuadProcessor() {}
118
119 const char* name() const override { return "MSAAQuadProcessor"; }
120
121 const Attribute* inPosition() const { return fInPosition; }
122 const Attribute* inUV() const { return fInUV; }
123 const Attribute* inColor() const { return fInColor; }
124 const SkMatrix& viewMatrix() const { return fViewMatrix; }
ethannicholas6536ae52016-05-02 12:16:49 -0700125
126 class GLSLProcessor : public GrGLSLGeometryProcessor {
127 public:
128 GLSLProcessor(const GrGeometryProcessor& qpr) {}
129
130 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
131 const MSAAQuadProcessor& qp = args.fGP.cast<MSAAQuadProcessor>();
132 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
133 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
134 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
135
136 // emit attributes
137 varyingHandler->emitAttributes(qp);
138 varyingHandler->addPassThroughAttribute(qp.inColor(), args.fOutputColor);
139
140 GrGLSLVertToFrag uv(kVec2f_GrSLType);
141 varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision);
142 vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qp.inUV()->fName);
143
144 // Setup position
bungeman06ca8ec2016-06-09 08:01:03 -0700145 this->setupPosition(vsBuilder, uniformHandler, gpArgs, qp.inPosition()->fName,
ethannicholas6536ae52016-05-02 12:16:49 -0700146 qp.viewMatrix(), &fViewMatrixUniform);
147
148 // emit transforms
bungeman06ca8ec2016-06-09 08:01:03 -0700149 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
150 qp.inPosition()->fName, SkMatrix::I(), args.fTransformsIn,
ethannicholas6536ae52016-05-02 12:16:49 -0700151 args.fTransformsOut);
152
153 GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
bungeman06ca8ec2016-06-09 08:01:03 -0700154 fsBuilder->codeAppendf("if (%s.x * %s.x >= %s.y) discard;", uv.fsIn(), uv.fsIn(),
ethannicholas6536ae52016-05-02 12:16:49 -0700155 uv.fsIn());
156 fsBuilder->codeAppendf("%s = vec4(1.0);", args.fOutputCoverage);
157 }
158
159 static inline void GenKey(const GrGeometryProcessor& gp,
160 const GrGLSLCaps&,
161 GrProcessorKeyBuilder* b) {
162 const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
163 uint32_t key = 0;
164 key |= qp.viewMatrix().hasPerspective() ? 0x1 : 0x0;
165 key |= qp.viewMatrix().isIdentity() ? 0x2: 0x0;
166 b->add32(key);
167 }
168
169 virtual void setData(const GrGLSLProgramDataManager& pdman,
170 const GrPrimitiveProcessor& gp) override {
171 const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
172 if (!qp.viewMatrix().isIdentity()) {
173 float viewMatrix[3 * 3];
174 GrGLSLGetMatrix<3>(viewMatrix, qp.viewMatrix());
175 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
176 }
177 }
178
ethannicholas6536ae52016-05-02 12:16:49 -0700179 private:
180 typedef GrGLSLGeometryProcessor INHERITED;
181
182 UniformHandle fViewMatrixUniform;
183 };
184
185 virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
186 GrProcessorKeyBuilder* b) const override {
187 GLSLProcessor::GenKey(*this, caps, b);
188 }
189
190 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
191 return new GLSLProcessor(*this);
192 }
193
194private:
195 MSAAQuadProcessor(const SkMatrix& viewMatrix)
196 : fViewMatrix(viewMatrix) {
197 this->initClassID<MSAAQuadProcessor>();
bsalomon6cb807b2016-08-17 11:33:39 -0700198 fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
199 kHigh_GrSLPrecision);
200 fInUV = &this->addVertexAttrib("inUV", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision);
201 fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
ethannicholas6536ae52016-05-02 12:16:49 -0700202 this->setSampleShading(1.0f);
203 }
204
205 const Attribute* fInPosition;
206 const Attribute* fInUV;
207 const Attribute* fInColor;
208 SkMatrix fViewMatrix;
bungeman06ca8ec2016-06-09 08:01:03 -0700209
ethannicholas6536ae52016-05-02 12:16:49 -0700210 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
211
212 typedef GrGeometryProcessor INHERITED;
213};
214
215class MSAAPathBatch : public GrVertexBatch {
216public:
217 DEFINE_BATCH_CLASS_ID
218
bsalomon8e9e45a2016-07-08 09:14:07 -0700219 MSAAPathBatch(GrColor color, const SkPath& path, const SkMatrix& viewMatrix,
220 const SkRect& devBounds)
bsalomon50c56a32016-06-30 12:05:32 -0700221 : INHERITED(ClassID())
222 , fViewMatrix(viewMatrix) {
223 fPaths.emplace_back(PathInfo{color, path});
bsalomon8e9e45a2016-07-08 09:14:07 -0700224 this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo);
bsalomon50c56a32016-06-30 12:05:32 -0700225 int contourCount;
226 this->computeWorstCasePointCount(path, &contourCount, &fMaxLineVertices, &fMaxQuadVertices);
227 fMaxLineIndices = fMaxLineVertices * 3;
228 fMaxQuadIndices = fMaxQuadVertices * 3;
229 fIsIndexed = contourCount > 1;
ethannicholas6536ae52016-05-02 12:16:49 -0700230 }
231
232 const char* name() const override { return "MSAAPathBatch"; }
233
bungeman06ca8ec2016-06-09 08:01:03 -0700234 void computePipelineOptimizations(GrInitInvariantOutput* color,
ethannicholas6536ae52016-05-02 12:16:49 -0700235 GrInitInvariantOutput* coverage,
236 GrBatchToXPOverrides* overrides) const override {
bsalomon50c56a32016-06-30 12:05:32 -0700237 // When this is called on a batch, there is only one path
238 color->setKnownFourComponents(fPaths[0].fColor);
ethannicholas6536ae52016-05-02 12:16:49 -0700239 coverage->setKnownSingleComponent(0xff);
240 }
241
242 bool isValid() const {
243 return !fIsIndexed || fMaxLineIndices <= SK_MaxU16;
244 }
245
246private:
247 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
248 // Handle any color overrides
249 if (!overrides.readsColor()) {
bsalomon50c56a32016-06-30 12:05:32 -0700250 fPaths[0].fColor = GrColor_ILLEGAL;
ethannicholas6536ae52016-05-02 12:16:49 -0700251 }
bsalomon50c56a32016-06-30 12:05:32 -0700252 overrides.getOverrideColorIfSet(&fPaths[0].fColor);
ethannicholas6536ae52016-05-02 12:16:49 -0700253 }
254
bsalomon50c56a32016-06-30 12:05:32 -0700255 void computeWorstCasePointCount(const SkPath& path, int* subpaths, int* outLinePointCount,
256 int* outQuadPointCount) const {
ethannicholas6536ae52016-05-02 12:16:49 -0700257 int linePointCount = 0;
258 int quadPointCount = 0;
259 *subpaths = 1;
260
261 bool first = true;
262
263 SkPath::Iter iter(path, false);
264 SkPath::Verb verb;
265
266 SkPoint pts[4];
267 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
268 switch (verb) {
269 case SkPath::kLine_Verb:
270 linePointCount += 1;
271 break;
272 case SkPath::kConic_Verb: {
273 SkScalar weight = iter.conicWeight();
274 SkAutoConicToQuads converter;
275 converter.computeQuads(pts, weight, kTolerance);
276 int quadPts = converter.countQuads();
277 linePointCount += quadPts;
278 quadPointCount += 3 * quadPts;
279 }
280 case SkPath::kQuad_Verb:
281 linePointCount += 1;
282 quadPointCount += 3;
283 break;
284 case SkPath::kCubic_Verb: {
285 SkSTArray<15, SkPoint, true> quadPts;
286 GrPathUtils::convertCubicToQuads(pts, kTolerance, &quadPts);
287 int count = quadPts.count();
288 linePointCount += count / 3;
289 quadPointCount += count;
290 break;
291 }
292 case SkPath::kMove_Verb:
293 linePointCount += 1;
294 if (!first) {
295 ++(*subpaths);
296 }
297 break;
298 default:
299 break;
300 }
301 first = false;
302 }
303 *outLinePointCount = linePointCount;
304 *outQuadPointCount = quadPointCount;
305 }
306
307 void onPrepareDraws(Target* target) const override {
308 SkASSERT(this->isValid());
309 if (fMaxLineVertices == 0) {
310 SkASSERT(fMaxQuadVertices == 0);
311 return;
312 }
313
bungeman06ca8ec2016-06-09 08:01:03 -0700314 GrPrimitiveType primitiveType = fIsIndexed ? kTriangles_GrPrimitiveType
ethannicholas6536ae52016-05-02 12:16:49 -0700315 : kTriangleFan_GrPrimitiveType;
316
317 // allocate vertex / index buffers
318 const GrBuffer* lineVertexBuffer;
319 int firstLineVertex;
320 MSAALineVertices lines;
321 size_t lineVertexStride = sizeof(MSAALineVertices::Vertex);
bungeman06ca8ec2016-06-09 08:01:03 -0700322 lines.vertices = (MSAALineVertices::Vertex*) target->makeVertexSpace(lineVertexStride,
ethannicholas6536ae52016-05-02 12:16:49 -0700323 fMaxLineVertices,
bungeman06ca8ec2016-06-09 08:01:03 -0700324 &lineVertexBuffer,
ethannicholas6536ae52016-05-02 12:16:49 -0700325 &firstLineVertex);
326 if (!lines.vertices) {
327 SkDebugf("Could not allocate vertices\n");
328 return;
329 }
330 lines.nextVertex = lines.vertices;
331 SkDEBUGCODE(lines.verticesEnd = lines.vertices + fMaxLineVertices;)
332
333 MSAAQuadVertices quads;
334 size_t quadVertexStride = sizeof(MSAAQuadVertices::Vertex);
335 SkAutoFree quadVertexPtr(sk_malloc_throw(fMaxQuadVertices * quadVertexStride));
336 quads.vertices = (MSAAQuadVertices::Vertex*) quadVertexPtr.get();
337 quads.nextVertex = quads.vertices;
338 SkDEBUGCODE(quads.verticesEnd = quads.vertices + fMaxQuadVertices;)
339
340 const GrBuffer* lineIndexBuffer = nullptr;
341 int firstLineIndex;
342 if (fIsIndexed) {
bungeman06ca8ec2016-06-09 08:01:03 -0700343 lines.indices = target->makeIndexSpace(fMaxLineIndices, &lineIndexBuffer,
ethannicholas6536ae52016-05-02 12:16:49 -0700344 &firstLineIndex);
345 if (!lines.indices) {
346 SkDebugf("Could not allocate indices\n");
347 return;
348 }
349 lines.nextIndex = lines.indices;
350 } else {
351 lines.indices = nullptr;
352 lines.nextIndex = nullptr;
353 }
354
355 SkAutoFree quadIndexPtr;
356 if (fIsIndexed) {
357 quads.indices = (uint16_t*) sk_malloc_throw(fMaxQuadIndices * sizeof(uint16_t));
358 quadIndexPtr.set(quads.indices);
359 quads.nextIndex = quads.indices;
360 } else {
361 quads.indices = nullptr;
362 quads.nextIndex = nullptr;
363 }
364
365 // fill buffers
bsalomon50c56a32016-06-30 12:05:32 -0700366 for (int i = 0; i < fPaths.count(); i++) {
367 const PathInfo& pathInfo = fPaths[i];
ethannicholas6536ae52016-05-02 12:16:49 -0700368
369 if (!this->createGeom(lines,
370 quads,
bsalomon50c56a32016-06-30 12:05:32 -0700371 pathInfo.fPath,
ethannicholas6536ae52016-05-02 12:16:49 -0700372 fViewMatrix,
bsalomon50c56a32016-06-30 12:05:32 -0700373 pathInfo.fColor,
ethannicholas6536ae52016-05-02 12:16:49 -0700374 fIsIndexed)) {
375 return;
376 }
377 }
378 int lineVertexOffset = (int) (lines.nextVertex - lines.vertices);
379 int lineIndexOffset = (int) (lines.nextIndex - lines.indices);
380 SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= fMaxLineIndices);
381 int quadVertexOffset = (int) (quads.nextVertex - quads.vertices);
382 int quadIndexOffset = (int) (quads.nextIndex - quads.indices);
383 SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= fMaxQuadIndices);
384
385 if (lineVertexOffset) {
bungeman06ca8ec2016-06-09 08:01:03 -0700386 sk_sp<GrGeometryProcessor> lineGP;
ethannicholas6536ae52016-05-02 12:16:49 -0700387 {
388 using namespace GrDefaultGeoProcFactory;
bungeman06ca8ec2016-06-09 08:01:03 -0700389 lineGP = GrDefaultGeoProcFactory::Make(Color(Color::kAttribute_Type),
390 Coverage(255),
391 LocalCoords(LocalCoords::kUnused_Type),
392 fViewMatrix);
ethannicholas6536ae52016-05-02 12:16:49 -0700393 }
394 SkASSERT(lineVertexStride == lineGP->getVertexStride());
395
396 GrMesh lineMeshes;
397 if (fIsIndexed) {
bungeman06ca8ec2016-06-09 08:01:03 -0700398 lineMeshes.initIndexed(primitiveType, lineVertexBuffer, lineIndexBuffer,
399 firstLineVertex, firstLineIndex, lineVertexOffset,
ethannicholas6536ae52016-05-02 12:16:49 -0700400 lineIndexOffset);
401 } else {
bungeman06ca8ec2016-06-09 08:01:03 -0700402 lineMeshes.init(primitiveType, lineVertexBuffer, firstLineVertex,
ethannicholas6536ae52016-05-02 12:16:49 -0700403 lineVertexOffset);
404 }
bungeman06ca8ec2016-06-09 08:01:03 -0700405 target->draw(lineGP.get(), lineMeshes);
ethannicholas6536ae52016-05-02 12:16:49 -0700406 }
407
408 if (quadVertexOffset) {
409 SkAutoTUnref<const GrGeometryProcessor> quadGP(MSAAQuadProcessor::Create(fViewMatrix));
410 SkASSERT(quadVertexStride == quadGP->getVertexStride());
411
412 const GrBuffer* quadVertexBuffer;
413 int firstQuadVertex;
bungeman06ca8ec2016-06-09 08:01:03 -0700414 MSAAQuadVertices::Vertex* quadVertices = (MSAAQuadVertices::Vertex*)
ethannicholas6536ae52016-05-02 12:16:49 -0700415 target->makeVertexSpace(quadVertexStride, quadVertexOffset, &quadVertexBuffer,
416 &firstQuadVertex);
417 memcpy(quadVertices, quads.vertices, quadVertexStride * quadVertexOffset);
418 GrMesh quadMeshes;
419 if (fIsIndexed) {
420 const GrBuffer* quadIndexBuffer;
421 int firstQuadIndex;
bungeman06ca8ec2016-06-09 08:01:03 -0700422 uint16_t* quadIndices = (uint16_t*) target->makeIndexSpace(quadIndexOffset,
423 &quadIndexBuffer,
ethannicholas6536ae52016-05-02 12:16:49 -0700424 &firstQuadIndex);
425 memcpy(quadIndices, quads.indices, sizeof(uint16_t) * quadIndexOffset);
bungeman06ca8ec2016-06-09 08:01:03 -0700426 quadMeshes.initIndexed(kTriangles_GrPrimitiveType, quadVertexBuffer,
427 quadIndexBuffer, firstQuadVertex, firstQuadIndex,
ethannicholas6536ae52016-05-02 12:16:49 -0700428 quadVertexOffset, quadIndexOffset);
429 } else {
bungeman06ca8ec2016-06-09 08:01:03 -0700430 quadMeshes.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex,
ethannicholas6536ae52016-05-02 12:16:49 -0700431 quadVertexOffset);
432 }
433 target->draw(quadGP, quadMeshes);
434 }
435 }
436
ethannicholas6536ae52016-05-02 12:16:49 -0700437 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
438 MSAAPathBatch* that = t->cast<MSAAPathBatch>();
439 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
440 that->bounds(), caps)) {
441 return false;
442 }
443
444 if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
445 return false;
446 }
447
bungeman06ca8ec2016-06-09 08:01:03 -0700448 if ((fMaxLineIndices + that->fMaxLineIndices > SK_MaxU16) ||
ethannicholas6536ae52016-05-02 12:16:49 -0700449 (fMaxQuadIndices + that->fMaxQuadIndices > SK_MaxU16)) {
450 return false;
451 }
452
bsalomon50c56a32016-06-30 12:05:32 -0700453 fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
bsalomon88cf17d2016-07-08 06:40:56 -0700454 this->joinBounds(*that);
ethannicholas6536ae52016-05-02 12:16:49 -0700455 fIsIndexed = true;
456 fMaxLineVertices += that->fMaxLineVertices;
457 fMaxQuadVertices += that->fMaxQuadVertices;
458 fMaxLineIndices += that->fMaxLineIndices;
459 fMaxQuadIndices += that->fMaxQuadIndices;
460 return true;
461 }
462
463 bool createGeom(MSAALineVertices& lines,
464 MSAAQuadVertices& quads,
465 const SkPath& path,
ethannicholas6536ae52016-05-02 12:16:49 -0700466 const SkMatrix& m,
467 SkColor color,
468 bool isIndexed) const {
469 {
470 uint16_t subpathIdxStart = (uint16_t) (lines.nextVertex - lines.vertices);
471
472 SkPoint pts[4];
473
474 bool first = true;
475 SkPath::Iter iter(path, false);
476
477 bool done = false;
478 while (!done) {
479 SkPath::Verb verb = iter.next(pts);
480 switch (verb) {
481 case SkPath::kMove_Verb:
482 if (!first) {
483 uint16_t currIdx = (uint16_t) (lines.nextVertex - lines.vertices);
484 subpathIdxStart = currIdx;
485 }
486 SkASSERT(lines.nextVertex < lines.verticesEnd);
487 *(lines.nextVertex++) = { pts[0], color };
488 break;
489 case SkPath::kLine_Verb:
490 if (isIndexed) {
491 uint16_t prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
492 if (prevIdx > subpathIdxStart) {
493 append_contour_edge_indices(subpathIdxStart, prevIdx, lines);
494 }
495 }
496 SkASSERT(lines.nextVertex < lines.verticesEnd);
497 *(lines.nextVertex++) = { pts[1], color };
498 break;
499 case SkPath::kConic_Verb: {
500 SkScalar weight = iter.conicWeight();
501 SkAutoConicToQuads converter;
bsalomon50c56a32016-06-30 12:05:32 -0700502 const SkPoint* quadPts = converter.computeQuads(pts, weight, kTolerance);
ethannicholas6536ae52016-05-02 12:16:49 -0700503 for (int i = 0; i < converter.countQuads(); ++i) {
bungeman06ca8ec2016-06-09 08:01:03 -0700504 add_quad(lines, quads, quadPts + i * 2, color, isIndexed,
ethannicholas6536ae52016-05-02 12:16:49 -0700505 subpathIdxStart);
506 }
507 break;
508 }
509 case SkPath::kQuad_Verb: {
510 add_quad(lines, quads, pts, color, isIndexed, subpathIdxStart);
bungeman06ca8ec2016-06-09 08:01:03 -0700511 break;
ethannicholas6536ae52016-05-02 12:16:49 -0700512 }
513 case SkPath::kCubic_Verb: {
514 SkSTArray<15, SkPoint, true> quadPts;
515 GrPathUtils::convertCubicToQuads(pts, kTolerance, &quadPts);
516 int count = quadPts.count();
517 for (int i = 0; i < count; i += 3) {
518 add_quad(lines, quads, &quadPts[i], color, isIndexed, subpathIdxStart);
519 }
520 break;
521 }
522 case SkPath::kClose_Verb:
523 break;
524 case SkPath::kDone_Verb:
525 done = true;
526 }
527 first = false;
528 }
529 }
530 return true;
531 }
532
bsalomon50c56a32016-06-30 12:05:32 -0700533 struct PathInfo {
534 GrColor fColor;
535 SkPath fPath;
536 };
537
538 SkSTArray<1, PathInfo, true> fPaths;
ethannicholas6536ae52016-05-02 12:16:49 -0700539
540 SkMatrix fViewMatrix;
541 int fMaxLineVertices;
542 int fMaxQuadVertices;
543 int fMaxLineIndices;
544 int fMaxQuadIndices;
545 bool fIsIndexed;
546
547 typedef GrVertexBatch INHERITED;
548};
549
robertphillips976f5f02016-06-03 10:59:20 -0700550bool GrMSAAPathRenderer::internalDrawPath(GrDrawContext* drawContext,
551 const GrPaint& paint,
robertphillipsd2b6d642016-07-21 08:55:08 -0700552 const GrUserStencilSettings& userStencilSettings,
cdalton862cff32016-05-12 15:09:48 -0700553 const GrClip& clip,
ethannicholas6536ae52016-05-02 12:16:49 -0700554 const SkMatrix& viewMatrix,
bsalomon8acedde2016-06-24 10:42:16 -0700555 const GrShape& shape,
ethannicholas6536ae52016-05-02 12:16:49 -0700556 bool stencilOnly) {
bsalomon8acedde2016-06-24 10:42:16 -0700557 SkASSERT(shape.style().isSimpleFill());
558 SkPath path;
559 shape.asPath(&path);
560
robertphillips8e375302016-07-11 10:43:58 -0700561 static const int kMaxNumPasses = 2;
562
cdalton93a379b2016-05-11 13:58:08 -0700563 int passCount = 0;
robertphillips8e375302016-07-11 10:43:58 -0700564 const GrUserStencilSettings* passes[kMaxNumPasses];
cdalton93a379b2016-05-11 13:58:08 -0700565 bool reverse = false;
566 bool lastPassIsBounds;
ethannicholas6536ae52016-05-02 12:16:49 -0700567
bsalomon8acedde2016-06-24 10:42:16 -0700568 if (single_pass_shape(shape)) {
ethannicholas6536ae52016-05-02 12:16:49 -0700569 passCount = 1;
570 if (stencilOnly) {
571 passes[0] = &gDirectToStencil;
572 } else {
robertphillipsd2b6d642016-07-21 08:55:08 -0700573 passes[0] = &userStencilSettings;
ethannicholas6536ae52016-05-02 12:16:49 -0700574 }
ethannicholas6536ae52016-05-02 12:16:49 -0700575 lastPassIsBounds = false;
576 } else {
577 switch (path.getFillType()) {
578 case SkPath::kInverseEvenOdd_FillType:
579 reverse = true;
580 // fallthrough
581 case SkPath::kEvenOdd_FillType:
582 passes[0] = &gEOStencilPass;
583 if (stencilOnly) {
584 passCount = 1;
585 lastPassIsBounds = false;
586 } else {
587 passCount = 2;
588 lastPassIsBounds = true;
589 if (reverse) {
590 passes[1] = &gInvEOColorPass;
591 } else {
592 passes[1] = &gEOColorPass;
593 }
594 }
ethannicholas6536ae52016-05-02 12:16:49 -0700595 break;
596
597 case SkPath::kInverseWinding_FillType:
598 reverse = true;
599 // fallthrough
600 case SkPath::kWinding_FillType:
601 passes[0] = &gWindStencilSeparateWithWrap;
602 passCount = 2;
ethannicholas6536ae52016-05-02 12:16:49 -0700603 if (stencilOnly) {
604 lastPassIsBounds = false;
robertphillips8e375302016-07-11 10:43:58 -0700605 passCount = 1;
ethannicholas6536ae52016-05-02 12:16:49 -0700606 } else {
607 lastPassIsBounds = true;
ethannicholas6536ae52016-05-02 12:16:49 -0700608 if (reverse) {
robertphillips8e375302016-07-11 10:43:58 -0700609 passes[1] = &gInvWindColorPass;
ethannicholas6536ae52016-05-02 12:16:49 -0700610 } else {
robertphillips8e375302016-07-11 10:43:58 -0700611 passes[1] = &gWindColorPass;
ethannicholas6536ae52016-05-02 12:16:49 -0700612 }
613 }
614 break;
615 default:
616 SkDEBUGFAIL("Unknown path fFill!");
617 return false;
618 }
619 }
620
621 SkRect devBounds;
robertphillips976f5f02016-06-03 10:59:20 -0700622 GetPathDevBounds(path, drawContext->width(), drawContext->height(), viewMatrix, &devBounds);
ethannicholas6536ae52016-05-02 12:16:49 -0700623
robertphillips8e375302016-07-11 10:43:58 -0700624 SkASSERT(passCount <= kMaxNumPasses);
625
ethannicholas6536ae52016-05-02 12:16:49 -0700626 for (int p = 0; p < passCount; ++p) {
ethannicholas6536ae52016-05-02 12:16:49 -0700627 if (lastPassIsBounds && (p == passCount-1)) {
ethannicholas6536ae52016-05-02 12:16:49 -0700628 SkRect bounds;
629 SkMatrix localMatrix = SkMatrix::I();
630 if (reverse) {
ethannicholas6536ae52016-05-02 12:16:49 -0700631 // draw over the dev bounds (which will be the whole dst surface for inv fill).
632 bounds = devBounds;
633 SkMatrix vmi;
634 // mapRect through persp matrix may not be correct
635 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
636 vmi.mapRect(&bounds);
637 } else {
638 if (!viewMatrix.invert(&localMatrix)) {
639 return false;
640 }
641 }
642 } else {
643 bounds = path.getBounds();
644 }
645 const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
646 viewMatrix;
647 SkAutoTUnref<GrDrawBatch> batch(
robertphillips3950f0d2016-07-07 07:33:13 -0700648 GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewM, bounds, nullptr,
ethannicholas6536ae52016-05-02 12:16:49 -0700649 &localMatrix));
robertphillips976f5f02016-06-03 10:59:20 -0700650
bsalomonbb243832016-07-22 07:10:19 -0700651 GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint));
652 pipelineBuilder.setUserStencil(passes[p]);
653
654 drawContext->drawBatch(pipelineBuilder, clip, batch);
robertphillips976f5f02016-06-03 10:59:20 -0700655 } else {
bsalomon88cf17d2016-07-08 06:40:56 -0700656 SkAutoTUnref<MSAAPathBatch> batch(new MSAAPathBatch(paint.getColor(), path,
bsalomon8e9e45a2016-07-08 09:14:07 -0700657 viewMatrix, devBounds));
robertphillips976f5f02016-06-03 10:59:20 -0700658 if (!batch->isValid()) {
ethannicholas6536ae52016-05-02 12:16:49 -0700659 return false;
660 }
robertphillips976f5f02016-06-03 10:59:20 -0700661
bsalomonbb243832016-07-22 07:10:19 -0700662 GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint));
663 pipelineBuilder.setUserStencil(passes[p]);
robertphillips976f5f02016-06-03 10:59:20 -0700664 if (passCount > 1) {
bsalomonbb243832016-07-22 07:10:19 -0700665 pipelineBuilder.setDisableColorXPFactory();
robertphillips976f5f02016-06-03 10:59:20 -0700666 }
667
bsalomonbb243832016-07-22 07:10:19 -0700668 drawContext->drawBatch(pipelineBuilder, clip, batch);
ethannicholas6536ae52016-05-02 12:16:49 -0700669 }
670 }
671 return true;
672}
673
674bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
bsalomonee432412016-06-27 07:18:18 -0700675 // This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are
676 // handled by passing on the original shape and letting the caller compute the stroked shape
677 // which will have a fill style.
678 return args.fShape->style().isSimpleFill() && !args.fAntiAlias;
ethannicholas6536ae52016-05-02 12:16:49 -0700679}
680
681bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
robertphillips976f5f02016-06-03 10:59:20 -0700682 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
683 "GrMSAAPathRenderer::onDrawPath");
bsalomon8acedde2016-06-24 10:42:16 -0700684 SkTLazy<GrShape> tmpShape;
685 const GrShape* shape = args.fShape;
686 if (shape->style().applies()) {
bsalomon6663acf2016-05-10 09:14:17 -0700687 SkScalar styleScale = GrStyle::MatrixToScaleFactor(*args.fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700688 tmpShape.init(args.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale));
689 shape = tmpShape.get();
ethannicholas6536ae52016-05-02 12:16:49 -0700690 }
robertphillips976f5f02016-06-03 10:59:20 -0700691 return this->internalDrawPath(args.fDrawContext,
692 *args.fPaint,
robertphillipsd2b6d642016-07-21 08:55:08 -0700693 *args.fUserStencilSettings,
cdalton862cff32016-05-12 15:09:48 -0700694 *args.fClip,
ethannicholas6536ae52016-05-02 12:16:49 -0700695 *args.fViewMatrix,
bsalomon8acedde2016-06-24 10:42:16 -0700696 *shape,
ethannicholas6536ae52016-05-02 12:16:49 -0700697 false);
698}
699
700void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) {
robertphillips976f5f02016-06-03 10:59:20 -0700701 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
702 "GrMSAAPathRenderer::onStencilPath");
bsalomon8acedde2016-06-24 10:42:16 -0700703 SkASSERT(args.fShape->style().isSimpleFill());
704 SkASSERT(!args.fShape->mayBeInverseFilledAfterStyling());
robertphillips976f5f02016-06-03 10:59:20 -0700705
706 GrPaint paint;
bungeman06ca8ec2016-06-09 08:01:03 -0700707 paint.setXPFactory(GrDisableColorXPFactory::Make());
robertphillips976f5f02016-06-03 10:59:20 -0700708 paint.setAntiAlias(args.fIsAA);
709
robertphillipsd2b6d642016-07-21 08:55:08 -0700710 this->internalDrawPath(args.fDrawContext, paint, GrUserStencilSettings::kUnused, *args.fClip,
robertphillips3950f0d2016-07-07 07:33:13 -0700711 *args.fViewMatrix, *args.fShape, true);
ethannicholas6536ae52016-05-02 12:16:49 -0700712}
713
714///////////////////////////////////////////////////////////////////////////////////////////////////