blob: 31b9ebf48c29dbe64b277243609d6a24951c94bd [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"
16#include "GrPipelineBuilder.h"
17#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; }
125 const SkMatrix& localMatrix() const { return SkMatrix::I(); }
126
127 class GLSLProcessor : public GrGLSLGeometryProcessor {
128 public:
129 GLSLProcessor(const GrGeometryProcessor& qpr) {}
130
131 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
132 const MSAAQuadProcessor& qp = args.fGP.cast<MSAAQuadProcessor>();
133 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
134 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
135 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
136
137 // emit attributes
138 varyingHandler->emitAttributes(qp);
139 varyingHandler->addPassThroughAttribute(qp.inColor(), args.fOutputColor);
140
141 GrGLSLVertToFrag uv(kVec2f_GrSLType);
142 varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision);
143 vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qp.inUV()->fName);
144
145 // Setup position
bungeman06ca8ec2016-06-09 08:01:03 -0700146 this->setupPosition(vsBuilder, uniformHandler, gpArgs, qp.inPosition()->fName,
ethannicholas6536ae52016-05-02 12:16:49 -0700147 qp.viewMatrix(), &fViewMatrixUniform);
148
149 // emit transforms
bungeman06ca8ec2016-06-09 08:01:03 -0700150 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
151 qp.inPosition()->fName, SkMatrix::I(), args.fTransformsIn,
ethannicholas6536ae52016-05-02 12:16:49 -0700152 args.fTransformsOut);
153
154 GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
bungeman06ca8ec2016-06-09 08:01:03 -0700155 fsBuilder->codeAppendf("if (%s.x * %s.x >= %s.y) discard;", uv.fsIn(), uv.fsIn(),
ethannicholas6536ae52016-05-02 12:16:49 -0700156 uv.fsIn());
157 fsBuilder->codeAppendf("%s = vec4(1.0);", args.fOutputCoverage);
158 }
159
160 static inline void GenKey(const GrGeometryProcessor& gp,
161 const GrGLSLCaps&,
162 GrProcessorKeyBuilder* b) {
163 const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
164 uint32_t key = 0;
165 key |= qp.viewMatrix().hasPerspective() ? 0x1 : 0x0;
166 key |= qp.viewMatrix().isIdentity() ? 0x2: 0x0;
167 b->add32(key);
168 }
169
170 virtual void setData(const GrGLSLProgramDataManager& pdman,
171 const GrPrimitiveProcessor& gp) override {
172 const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
173 if (!qp.viewMatrix().isIdentity()) {
174 float viewMatrix[3 * 3];
175 GrGLSLGetMatrix<3>(viewMatrix, qp.viewMatrix());
176 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
177 }
178 }
179
180 void setTransformData(const GrPrimitiveProcessor& primProc,
181 const GrGLSLProgramDataManager& pdman,
182 int index,
183 const SkTArray<const GrCoordTransform*, true>& transforms) override {
184 this->setTransformDataHelper<MSAAQuadProcessor>(primProc, pdman, index, transforms);
185 }
186
187 private:
188 typedef GrGLSLGeometryProcessor INHERITED;
189
190 UniformHandle fViewMatrixUniform;
191 };
192
193 virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
194 GrProcessorKeyBuilder* b) const override {
195 GLSLProcessor::GenKey(*this, caps, b);
196 }
197
198 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
199 return new GLSLProcessor(*this);
200 }
201
202private:
203 MSAAQuadProcessor(const SkMatrix& viewMatrix)
204 : fViewMatrix(viewMatrix) {
205 this->initClassID<MSAAQuadProcessor>();
bungeman06ca8ec2016-06-09 08:01:03 -0700206 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
ethannicholas6536ae52016-05-02 12:16:49 -0700207 kHigh_GrSLPrecision));
bungeman06ca8ec2016-06-09 08:01:03 -0700208 fInUV = &this->addVertexAttrib(Attribute("inUV", kVec2f_GrVertexAttribType,
ethannicholas6536ae52016-05-02 12:16:49 -0700209 kHigh_GrSLPrecision));
210 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
211 this->setSampleShading(1.0f);
212 }
213
214 const Attribute* fInPosition;
215 const Attribute* fInUV;
216 const Attribute* fInColor;
217 SkMatrix fViewMatrix;
bungeman06ca8ec2016-06-09 08:01:03 -0700218
ethannicholas6536ae52016-05-02 12:16:49 -0700219 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
220
221 typedef GrGeometryProcessor INHERITED;
222};
223
224class MSAAPathBatch : public GrVertexBatch {
225public:
226 DEFINE_BATCH_CLASS_ID
227
228 struct Geometry {
229 GrColor fColor;
230 SkPath fPath;
231 SkScalar fTolerance;
232 };
233
bungeman06ca8ec2016-06-09 08:01:03 -0700234 static MSAAPathBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix,
ethannicholas6536ae52016-05-02 12:16:49 -0700235 const SkRect& devBounds) {
236 return new MSAAPathBatch(geometry, viewMatrix, devBounds);
237 }
238
239 const char* name() const override { return "MSAAPathBatch"; }
240
bungeman06ca8ec2016-06-09 08:01:03 -0700241 void computePipelineOptimizations(GrInitInvariantOutput* color,
ethannicholas6536ae52016-05-02 12:16:49 -0700242 GrInitInvariantOutput* coverage,
243 GrBatchToXPOverrides* overrides) const override {
244 // When this is called on a batch, there is only one geometry bundle
245 color->setKnownFourComponents(fGeoData[0].fColor);
246 coverage->setKnownSingleComponent(0xff);
247 }
248
249 bool isValid() const {
250 return !fIsIndexed || fMaxLineIndices <= SK_MaxU16;
251 }
252
253private:
254 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
255 // Handle any color overrides
256 if (!overrides.readsColor()) {
257 fGeoData[0].fColor = GrColor_ILLEGAL;
258 }
259 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
260 }
261
bungeman06ca8ec2016-06-09 08:01:03 -0700262 void computeWorstCasePointCount(const SkPath& path, int* subpaths, SkScalar tol,
ethannicholas6536ae52016-05-02 12:16:49 -0700263 int* outLinePointCount, int* outQuadPointCount) const {
264 int linePointCount = 0;
265 int quadPointCount = 0;
266 *subpaths = 1;
267
268 bool first = true;
269
270 SkPath::Iter iter(path, false);
271 SkPath::Verb verb;
272
273 SkPoint pts[4];
274 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
275 switch (verb) {
276 case SkPath::kLine_Verb:
277 linePointCount += 1;
278 break;
279 case SkPath::kConic_Verb: {
280 SkScalar weight = iter.conicWeight();
281 SkAutoConicToQuads converter;
282 converter.computeQuads(pts, weight, kTolerance);
283 int quadPts = converter.countQuads();
284 linePointCount += quadPts;
285 quadPointCount += 3 * quadPts;
286 }
287 case SkPath::kQuad_Verb:
288 linePointCount += 1;
289 quadPointCount += 3;
290 break;
291 case SkPath::kCubic_Verb: {
292 SkSTArray<15, SkPoint, true> quadPts;
293 GrPathUtils::convertCubicToQuads(pts, kTolerance, &quadPts);
294 int count = quadPts.count();
295 linePointCount += count / 3;
296 quadPointCount += count;
297 break;
298 }
299 case SkPath::kMove_Verb:
300 linePointCount += 1;
301 if (!first) {
302 ++(*subpaths);
303 }
304 break;
305 default:
306 break;
307 }
308 first = false;
309 }
310 *outLinePointCount = linePointCount;
311 *outQuadPointCount = quadPointCount;
312 }
313
314 void onPrepareDraws(Target* target) const override {
315 SkASSERT(this->isValid());
316 if (fMaxLineVertices == 0) {
317 SkASSERT(fMaxQuadVertices == 0);
318 return;
319 }
320
bungeman06ca8ec2016-06-09 08:01:03 -0700321 GrPrimitiveType primitiveType = fIsIndexed ? kTriangles_GrPrimitiveType
ethannicholas6536ae52016-05-02 12:16:49 -0700322 : kTriangleFan_GrPrimitiveType;
323
324 // allocate vertex / index buffers
325 const GrBuffer* lineVertexBuffer;
326 int firstLineVertex;
327 MSAALineVertices lines;
328 size_t lineVertexStride = sizeof(MSAALineVertices::Vertex);
bungeman06ca8ec2016-06-09 08:01:03 -0700329 lines.vertices = (MSAALineVertices::Vertex*) target->makeVertexSpace(lineVertexStride,
ethannicholas6536ae52016-05-02 12:16:49 -0700330 fMaxLineVertices,
bungeman06ca8ec2016-06-09 08:01:03 -0700331 &lineVertexBuffer,
ethannicholas6536ae52016-05-02 12:16:49 -0700332 &firstLineVertex);
333 if (!lines.vertices) {
334 SkDebugf("Could not allocate vertices\n");
335 return;
336 }
337 lines.nextVertex = lines.vertices;
338 SkDEBUGCODE(lines.verticesEnd = lines.vertices + fMaxLineVertices;)
339
340 MSAAQuadVertices quads;
341 size_t quadVertexStride = sizeof(MSAAQuadVertices::Vertex);
342 SkAutoFree quadVertexPtr(sk_malloc_throw(fMaxQuadVertices * quadVertexStride));
343 quads.vertices = (MSAAQuadVertices::Vertex*) quadVertexPtr.get();
344 quads.nextVertex = quads.vertices;
345 SkDEBUGCODE(quads.verticesEnd = quads.vertices + fMaxQuadVertices;)
346
347 const GrBuffer* lineIndexBuffer = nullptr;
348 int firstLineIndex;
349 if (fIsIndexed) {
bungeman06ca8ec2016-06-09 08:01:03 -0700350 lines.indices = target->makeIndexSpace(fMaxLineIndices, &lineIndexBuffer,
ethannicholas6536ae52016-05-02 12:16:49 -0700351 &firstLineIndex);
352 if (!lines.indices) {
353 SkDebugf("Could not allocate indices\n");
354 return;
355 }
356 lines.nextIndex = lines.indices;
357 } else {
358 lines.indices = nullptr;
359 lines.nextIndex = nullptr;
360 }
361
362 SkAutoFree quadIndexPtr;
363 if (fIsIndexed) {
364 quads.indices = (uint16_t*) sk_malloc_throw(fMaxQuadIndices * sizeof(uint16_t));
365 quadIndexPtr.set(quads.indices);
366 quads.nextIndex = quads.indices;
367 } else {
368 quads.indices = nullptr;
369 quads.nextIndex = nullptr;
370 }
371
372 // fill buffers
373 for (int i = 0; i < fGeoData.count(); i++) {
374 const Geometry& args = fGeoData[i];
375
376 if (!this->createGeom(lines,
377 quads,
378 args.fPath,
379 args.fTolerance,
380 fViewMatrix,
381 args.fColor,
382 fIsIndexed)) {
383 return;
384 }
385 }
386 int lineVertexOffset = (int) (lines.nextVertex - lines.vertices);
387 int lineIndexOffset = (int) (lines.nextIndex - lines.indices);
388 SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= fMaxLineIndices);
389 int quadVertexOffset = (int) (quads.nextVertex - quads.vertices);
390 int quadIndexOffset = (int) (quads.nextIndex - quads.indices);
391 SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= fMaxQuadIndices);
392
393 if (lineVertexOffset) {
bungeman06ca8ec2016-06-09 08:01:03 -0700394 sk_sp<GrGeometryProcessor> lineGP;
ethannicholas6536ae52016-05-02 12:16:49 -0700395 {
396 using namespace GrDefaultGeoProcFactory;
bungeman06ca8ec2016-06-09 08:01:03 -0700397 lineGP = GrDefaultGeoProcFactory::Make(Color(Color::kAttribute_Type),
398 Coverage(255),
399 LocalCoords(LocalCoords::kUnused_Type),
400 fViewMatrix);
ethannicholas6536ae52016-05-02 12:16:49 -0700401 }
402 SkASSERT(lineVertexStride == lineGP->getVertexStride());
403
404 GrMesh lineMeshes;
405 if (fIsIndexed) {
bungeman06ca8ec2016-06-09 08:01:03 -0700406 lineMeshes.initIndexed(primitiveType, lineVertexBuffer, lineIndexBuffer,
407 firstLineVertex, firstLineIndex, lineVertexOffset,
ethannicholas6536ae52016-05-02 12:16:49 -0700408 lineIndexOffset);
409 } else {
bungeman06ca8ec2016-06-09 08:01:03 -0700410 lineMeshes.init(primitiveType, lineVertexBuffer, firstLineVertex,
ethannicholas6536ae52016-05-02 12:16:49 -0700411 lineVertexOffset);
412 }
bungeman06ca8ec2016-06-09 08:01:03 -0700413 target->draw(lineGP.get(), lineMeshes);
ethannicholas6536ae52016-05-02 12:16:49 -0700414 }
415
416 if (quadVertexOffset) {
417 SkAutoTUnref<const GrGeometryProcessor> quadGP(MSAAQuadProcessor::Create(fViewMatrix));
418 SkASSERT(quadVertexStride == quadGP->getVertexStride());
419
420 const GrBuffer* quadVertexBuffer;
421 int firstQuadVertex;
bungeman06ca8ec2016-06-09 08:01:03 -0700422 MSAAQuadVertices::Vertex* quadVertices = (MSAAQuadVertices::Vertex*)
ethannicholas6536ae52016-05-02 12:16:49 -0700423 target->makeVertexSpace(quadVertexStride, quadVertexOffset, &quadVertexBuffer,
424 &firstQuadVertex);
425 memcpy(quadVertices, quads.vertices, quadVertexStride * quadVertexOffset);
426 GrMesh quadMeshes;
427 if (fIsIndexed) {
428 const GrBuffer* quadIndexBuffer;
429 int firstQuadIndex;
bungeman06ca8ec2016-06-09 08:01:03 -0700430 uint16_t* quadIndices = (uint16_t*) target->makeIndexSpace(quadIndexOffset,
431 &quadIndexBuffer,
ethannicholas6536ae52016-05-02 12:16:49 -0700432 &firstQuadIndex);
433 memcpy(quadIndices, quads.indices, sizeof(uint16_t) * quadIndexOffset);
bungeman06ca8ec2016-06-09 08:01:03 -0700434 quadMeshes.initIndexed(kTriangles_GrPrimitiveType, quadVertexBuffer,
435 quadIndexBuffer, firstQuadVertex, firstQuadIndex,
ethannicholas6536ae52016-05-02 12:16:49 -0700436 quadVertexOffset, quadIndexOffset);
437 } else {
bungeman06ca8ec2016-06-09 08:01:03 -0700438 quadMeshes.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex,
ethannicholas6536ae52016-05-02 12:16:49 -0700439 quadVertexOffset);
440 }
441 target->draw(quadGP, quadMeshes);
442 }
443 }
444
445 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
446
447 MSAAPathBatch(const Geometry& geometry, const SkMatrix& viewMatrix, const SkRect& devBounds)
448 : INHERITED(ClassID())
449 , fViewMatrix(viewMatrix) {
450 fGeoData.push_back(geometry);
451 this->setBounds(devBounds);
452 int contourCount;
bungeman06ca8ec2016-06-09 08:01:03 -0700453 this->computeWorstCasePointCount(geometry.fPath, &contourCount, kTolerance,
ethannicholas6536ae52016-05-02 12:16:49 -0700454 &fMaxLineVertices, &fMaxQuadVertices);
455 fMaxLineIndices = fMaxLineVertices * 3;
456 fMaxQuadIndices = fMaxQuadVertices * 3;
457 fIsIndexed = contourCount > 1;
458 }
459
460 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
461 MSAAPathBatch* that = t->cast<MSAAPathBatch>();
462 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
463 that->bounds(), caps)) {
464 return false;
465 }
466
467 if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
468 return false;
469 }
470
bungeman06ca8ec2016-06-09 08:01:03 -0700471 if ((fMaxLineIndices + that->fMaxLineIndices > SK_MaxU16) ||
ethannicholas6536ae52016-05-02 12:16:49 -0700472 (fMaxQuadIndices + that->fMaxQuadIndices > SK_MaxU16)) {
473 return false;
474 }
475
476 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
477 this->joinBounds(that->bounds());
478 fIsIndexed = true;
479 fMaxLineVertices += that->fMaxLineVertices;
480 fMaxQuadVertices += that->fMaxQuadVertices;
481 fMaxLineIndices += that->fMaxLineIndices;
482 fMaxQuadIndices += that->fMaxQuadIndices;
483 return true;
484 }
485
486 bool createGeom(MSAALineVertices& lines,
487 MSAAQuadVertices& quads,
488 const SkPath& path,
489 SkScalar srcSpaceTol,
490 const SkMatrix& m,
491 SkColor color,
492 bool isIndexed) const {
493 {
494 uint16_t subpathIdxStart = (uint16_t) (lines.nextVertex - lines.vertices);
495
496 SkPoint pts[4];
497
498 bool first = true;
499 SkPath::Iter iter(path, false);
500
501 bool done = false;
502 while (!done) {
503 SkPath::Verb verb = iter.next(pts);
504 switch (verb) {
505 case SkPath::kMove_Verb:
506 if (!first) {
507 uint16_t currIdx = (uint16_t) (lines.nextVertex - lines.vertices);
508 subpathIdxStart = currIdx;
509 }
510 SkASSERT(lines.nextVertex < lines.verticesEnd);
511 *(lines.nextVertex++) = { pts[0], color };
512 break;
513 case SkPath::kLine_Verb:
514 if (isIndexed) {
515 uint16_t prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
516 if (prevIdx > subpathIdxStart) {
517 append_contour_edge_indices(subpathIdxStart, prevIdx, lines);
518 }
519 }
520 SkASSERT(lines.nextVertex < lines.verticesEnd);
521 *(lines.nextVertex++) = { pts[1], color };
522 break;
523 case SkPath::kConic_Verb: {
524 SkScalar weight = iter.conicWeight();
525 SkAutoConicToQuads converter;
bungeman06ca8ec2016-06-09 08:01:03 -0700526 const SkPoint* quadPts = converter.computeQuads(pts, weight,
ethannicholas6536ae52016-05-02 12:16:49 -0700527 kTolerance);
528 for (int i = 0; i < converter.countQuads(); ++i) {
bungeman06ca8ec2016-06-09 08:01:03 -0700529 add_quad(lines, quads, quadPts + i * 2, color, isIndexed,
ethannicholas6536ae52016-05-02 12:16:49 -0700530 subpathIdxStart);
531 }
532 break;
533 }
534 case SkPath::kQuad_Verb: {
535 add_quad(lines, quads, pts, color, isIndexed, subpathIdxStart);
bungeman06ca8ec2016-06-09 08:01:03 -0700536 break;
ethannicholas6536ae52016-05-02 12:16:49 -0700537 }
538 case SkPath::kCubic_Verb: {
539 SkSTArray<15, SkPoint, true> quadPts;
540 GrPathUtils::convertCubicToQuads(pts, kTolerance, &quadPts);
541 int count = quadPts.count();
542 for (int i = 0; i < count; i += 3) {
543 add_quad(lines, quads, &quadPts[i], color, isIndexed, subpathIdxStart);
544 }
545 break;
546 }
547 case SkPath::kClose_Verb:
548 break;
549 case SkPath::kDone_Verb:
550 done = true;
551 }
552 first = false;
553 }
554 }
555 return true;
556 }
557
558 SkSTArray<1, Geometry, true> fGeoData;
559
560 SkMatrix fViewMatrix;
561 int fMaxLineVertices;
562 int fMaxQuadVertices;
563 int fMaxLineIndices;
564 int fMaxQuadIndices;
565 bool fIsIndexed;
566
567 typedef GrVertexBatch INHERITED;
568};
569
robertphillips976f5f02016-06-03 10:59:20 -0700570bool GrMSAAPathRenderer::internalDrawPath(GrDrawContext* drawContext,
571 const GrPaint& paint,
572 const GrUserStencilSettings* userStencilSettings,
cdalton862cff32016-05-12 15:09:48 -0700573 const GrClip& clip,
ethannicholas6536ae52016-05-02 12:16:49 -0700574 GrColor color,
575 const SkMatrix& viewMatrix,
bsalomon8acedde2016-06-24 10:42:16 -0700576 const GrShape& shape,
ethannicholas6536ae52016-05-02 12:16:49 -0700577 bool stencilOnly) {
bsalomon8acedde2016-06-24 10:42:16 -0700578 SkASSERT(shape.style().isSimpleFill());
579 SkPath path;
580 shape.asPath(&path);
581
cdalton93a379b2016-05-11 13:58:08 -0700582 int passCount = 0;
583 const GrUserStencilSettings* passes[3];
584 GrPipelineBuilder::DrawFace drawFace[3];
585 bool reverse = false;
586 bool lastPassIsBounds;
ethannicholas6536ae52016-05-02 12:16:49 -0700587
bsalomon8acedde2016-06-24 10:42:16 -0700588 if (single_pass_shape(shape)) {
ethannicholas6536ae52016-05-02 12:16:49 -0700589 passCount = 1;
590 if (stencilOnly) {
591 passes[0] = &gDirectToStencil;
592 } else {
593 passes[0] = nullptr;
594 }
595 drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
596 lastPassIsBounds = false;
597 } else {
598 switch (path.getFillType()) {
599 case SkPath::kInverseEvenOdd_FillType:
600 reverse = true;
601 // fallthrough
602 case SkPath::kEvenOdd_FillType:
603 passes[0] = &gEOStencilPass;
604 if (stencilOnly) {
605 passCount = 1;
606 lastPassIsBounds = false;
607 } else {
608 passCount = 2;
609 lastPassIsBounds = true;
610 if (reverse) {
611 passes[1] = &gInvEOColorPass;
612 } else {
613 passes[1] = &gEOColorPass;
614 }
615 }
616 drawFace[0] = drawFace[1] = GrPipelineBuilder::kBoth_DrawFace;
617 break;
618
619 case SkPath::kInverseWinding_FillType:
620 reverse = true;
621 // fallthrough
622 case SkPath::kWinding_FillType:
623 passes[0] = &gWindStencilSeparateWithWrap;
624 passCount = 2;
625 drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
626 if (stencilOnly) {
627 lastPassIsBounds = false;
628 --passCount;
629 } else {
630 lastPassIsBounds = true;
631 drawFace[passCount-1] = GrPipelineBuilder::kBoth_DrawFace;
632 if (reverse) {
633 passes[passCount-1] = &gInvWindColorPass;
634 } else {
635 passes[passCount-1] = &gWindColorPass;
636 }
637 }
638 break;
639 default:
640 SkDEBUGFAIL("Unknown path fFill!");
641 return false;
642 }
643 }
644
645 SkRect devBounds;
robertphillips976f5f02016-06-03 10:59:20 -0700646 GetPathDevBounds(path, drawContext->width(), drawContext->height(), viewMatrix, &devBounds);
ethannicholas6536ae52016-05-02 12:16:49 -0700647
648 for (int p = 0; p < passCount; ++p) {
ethannicholas6536ae52016-05-02 12:16:49 -0700649 if (lastPassIsBounds && (p == passCount-1)) {
ethannicholas6536ae52016-05-02 12:16:49 -0700650 SkRect bounds;
651 SkMatrix localMatrix = SkMatrix::I();
652 if (reverse) {
ethannicholas6536ae52016-05-02 12:16:49 -0700653 // draw over the dev bounds (which will be the whole dst surface for inv fill).
654 bounds = devBounds;
655 SkMatrix vmi;
656 // mapRect through persp matrix may not be correct
657 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
658 vmi.mapRect(&bounds);
659 } else {
660 if (!viewMatrix.invert(&localMatrix)) {
661 return false;
662 }
663 }
664 } else {
665 bounds = path.getBounds();
666 }
667 const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
668 viewMatrix;
669 SkAutoTUnref<GrDrawBatch> batch(
670 GrRectBatchFactory::CreateNonAAFill(color, viewM, bounds, nullptr,
671 &localMatrix));
robertphillips976f5f02016-06-03 10:59:20 -0700672
csmartdaltonecbc12b2016-06-08 10:08:43 -0700673 GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint));
robertphillips976f5f02016-06-03 10:59:20 -0700674 pipelineBuilder.setDrawFace(drawFace[p]);
675 if (passes[p]) {
676 pipelineBuilder.setUserStencil(passes[p]);
677 } else {
678 pipelineBuilder.setUserStencil(userStencilSettings);
ethannicholas6536ae52016-05-02 12:16:49 -0700679 }
680
robertphillips976f5f02016-06-03 10:59:20 -0700681 drawContext->drawBatch(pipelineBuilder, clip, batch);
682 } else {
ethannicholas6536ae52016-05-02 12:16:49 -0700683 MSAAPathBatch::Geometry geometry;
684 geometry.fColor = color;
685 geometry.fPath = path;
686 geometry.fTolerance = kTolerance;
687
bungeman06ca8ec2016-06-09 08:01:03 -0700688 SkAutoTUnref<MSAAPathBatch> batch(MSAAPathBatch::Create(geometry, viewMatrix,
ethannicholas6536ae52016-05-02 12:16:49 -0700689 devBounds));
robertphillips976f5f02016-06-03 10:59:20 -0700690 if (!batch->isValid()) {
ethannicholas6536ae52016-05-02 12:16:49 -0700691 return false;
692 }
robertphillips976f5f02016-06-03 10:59:20 -0700693
csmartdaltonecbc12b2016-06-08 10:08:43 -0700694 GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint));
robertphillips976f5f02016-06-03 10:59:20 -0700695 pipelineBuilder.setDrawFace(drawFace[p]);
696 if (passes[p]) {
697 pipelineBuilder.setUserStencil(passes[p]);
698 } else {
699 pipelineBuilder.setUserStencil(userStencilSettings);
700 }
701 if (passCount > 1) {
702 pipelineBuilder.setDisableColorXPFactory();
703 }
704
705 drawContext->drawBatch(pipelineBuilder, clip, batch);
ethannicholas6536ae52016-05-02 12:16:49 -0700706 }
707 }
708 return true;
709}
710
711bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
bsalomon6663acf2016-05-10 09:14:17 -0700712 // This path renderer does not support hairlines. We defer on anything that could be handled
713 // as a hairline by another path renderer. Also, arbitrary path effects could produce
714 // a hairline result.
bsalomon8acedde2016-06-24 10:42:16 -0700715 return !IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr) &&
716 !args.fShape->style().couldBeHairline() && !args.fAntiAlias;
ethannicholas6536ae52016-05-02 12:16:49 -0700717}
718
719bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
robertphillips976f5f02016-06-03 10:59:20 -0700720 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
721 "GrMSAAPathRenderer::onDrawPath");
bsalomon8acedde2016-06-24 10:42:16 -0700722 SkTLazy<GrShape> tmpShape;
723 const GrShape* shape = args.fShape;
724 if (shape->style().applies()) {
bsalomon6663acf2016-05-10 09:14:17 -0700725 SkScalar styleScale = GrStyle::MatrixToScaleFactor(*args.fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700726 tmpShape.init(args.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale));
727 shape = tmpShape.get();
ethannicholas6536ae52016-05-02 12:16:49 -0700728 }
robertphillips976f5f02016-06-03 10:59:20 -0700729 return this->internalDrawPath(args.fDrawContext,
730 *args.fPaint,
731 args.fUserStencilSettings,
cdalton862cff32016-05-12 15:09:48 -0700732 *args.fClip,
ethannicholas6536ae52016-05-02 12:16:49 -0700733 args.fColor,
734 *args.fViewMatrix,
bsalomon8acedde2016-06-24 10:42:16 -0700735 *shape,
ethannicholas6536ae52016-05-02 12:16:49 -0700736 false);
737}
738
739void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) {
robertphillips976f5f02016-06-03 10:59:20 -0700740 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
741 "GrMSAAPathRenderer::onStencilPath");
bsalomon8acedde2016-06-24 10:42:16 -0700742 SkASSERT(args.fShape->style().isSimpleFill());
743 SkASSERT(!args.fShape->mayBeInverseFilledAfterStyling());
robertphillips976f5f02016-06-03 10:59:20 -0700744
745 GrPaint paint;
bungeman06ca8ec2016-06-09 08:01:03 -0700746 paint.setXPFactory(GrDisableColorXPFactory::Make());
robertphillips976f5f02016-06-03 10:59:20 -0700747 paint.setAntiAlias(args.fIsAA);
748
bsalomon8acedde2016-06-24 10:42:16 -0700749 this->internalDrawPath(args.fDrawContext, paint, &GrUserStencilSettings::kUnused, *args.fClip,
750 GrColor_WHITE, *args.fViewMatrix, *args.fShape, true);
ethannicholas6536ae52016-05-02 12:16:49 -0700751}
752
753///////////////////////////////////////////////////////////////////////////////////////////////////