Line data Source code
1 : /*
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 :
10 : #include "GrAuditTrail.h"
11 : #include "GrClip.h"
12 : #include "GrDefaultGeoProcFactory.h"
13 : #include "GrFixedClip.h"
14 : #include "GrMesh.h"
15 : #include "GrOpFlushState.h"
16 : #include "GrPathStencilSettings.h"
17 : #include "GrPathUtils.h"
18 : #include "GrPipelineBuilder.h"
19 : #include "SkAutoMalloc.h"
20 : #include "SkGeometry.h"
21 : #include "SkTraceEvent.h"
22 : #include "gl/GrGLVaryingHandler.h"
23 : #include "glsl/GrGLSLFragmentShaderBuilder.h"
24 : #include "glsl/GrGLSLGeometryProcessor.h"
25 : #include "glsl/GrGLSLProgramDataManager.h"
26 : #include "glsl/GrGLSLUtil.h"
27 : #include "glsl/GrGLSLVertexShaderBuilder.h"
28 : #include "ops/GrMeshDrawOp.h"
29 : #include "ops/GrRectOpFactory.h"
30 :
31 : static const float kTolerance = 0.5f;
32 :
33 : ////////////////////////////////////////////////////////////////////////////////
34 : // Helpers for drawPath
35 :
36 0 : static inline bool single_pass_shape(const GrShape& shape) {
37 0 : if (!shape.inverseFilled()) {
38 0 : return shape.knownToBeConvex();
39 : }
40 0 : return false;
41 : }
42 :
43 0 : GrPathRenderer::StencilSupport GrMSAAPathRenderer::onGetStencilSupport(const GrShape& shape) const {
44 0 : if (single_pass_shape(shape)) {
45 0 : return GrPathRenderer::kNoRestriction_StencilSupport;
46 : } else {
47 0 : return GrPathRenderer::kStencilOnly_StencilSupport;
48 : }
49 : }
50 :
51 : struct MSAALineVertices {
52 : struct Vertex {
53 : SkPoint fPosition;
54 : SkColor fColor;
55 : };
56 : Vertex* vertices;
57 : Vertex* nextVertex;
58 : #ifdef SK_DEBUG
59 : Vertex* verticesEnd;
60 : #endif
61 : uint16_t* indices;
62 : uint16_t* nextIndex;
63 : };
64 :
65 : struct MSAAQuadVertices {
66 : struct Vertex {
67 : SkPoint fPosition;
68 : SkPoint fUV;
69 : SkColor fColor;
70 : };
71 : Vertex* vertices;
72 : Vertex* nextVertex;
73 : #ifdef SK_DEBUG
74 : Vertex* verticesEnd;
75 : #endif
76 : uint16_t* indices;
77 : uint16_t* nextIndex;
78 : };
79 :
80 0 : static inline void append_contour_edge_indices(uint16_t fanCenterIdx,
81 : uint16_t edgeV0Idx,
82 : MSAALineVertices& lines) {
83 0 : *(lines.nextIndex++) = fanCenterIdx;
84 0 : *(lines.nextIndex++) = edgeV0Idx;
85 0 : *(lines.nextIndex++) = edgeV0Idx + 1;
86 0 : }
87 :
88 0 : static inline void add_quad(MSAALineVertices& lines, MSAAQuadVertices& quads, const SkPoint pts[],
89 : SkColor color, bool indexed, uint16_t subpathLineIdxStart) {
90 0 : SkASSERT(lines.nextVertex < lines.verticesEnd);
91 0 : *lines.nextVertex = { pts[2], color };
92 0 : if (indexed) {
93 0 : int prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
94 0 : if (prevIdx > subpathLineIdxStart) {
95 0 : append_contour_edge_indices(subpathLineIdxStart, prevIdx, lines);
96 : }
97 : }
98 0 : lines.nextVertex++;
99 :
100 0 : SkASSERT(quads.nextVertex + 2 < quads.verticesEnd);
101 : // the texture coordinates are drawn from the Loop-Blinn rendering algorithm
102 0 : *(quads.nextVertex++) = { pts[0], SkPoint::Make(0.0, 0.0), color };
103 0 : *(quads.nextVertex++) = { pts[1], SkPoint::Make(0.5, 0.0), color };
104 0 : *(quads.nextVertex++) = { pts[2], SkPoint::Make(1.0, 1.0), color };
105 0 : if (indexed) {
106 0 : uint16_t offset = (uint16_t) (quads.nextVertex - quads.vertices) - 3;
107 0 : *(quads.nextIndex++) = offset++;
108 0 : *(quads.nextIndex++) = offset++;
109 0 : *(quads.nextIndex++) = offset++;
110 : }
111 0 : }
112 :
113 : class MSAAQuadProcessor : public GrGeometryProcessor {
114 : public:
115 0 : static GrGeometryProcessor* Create(const SkMatrix& viewMatrix) {
116 0 : return new MSAAQuadProcessor(viewMatrix);
117 : }
118 :
119 0 : ~MSAAQuadProcessor() override {}
120 :
121 0 : const char* name() const override { return "MSAAQuadProcessor"; }
122 :
123 0 : const Attribute* inPosition() const { return fInPosition; }
124 0 : const Attribute* inUV() const { return fInUV; }
125 0 : const Attribute* inColor() const { return fInColor; }
126 0 : const SkMatrix& viewMatrix() const { return fViewMatrix; }
127 :
128 0 : class GLSLProcessor : public GrGLSLGeometryProcessor {
129 : public:
130 0 : GLSLProcessor(const GrGeometryProcessor& qpr) {}
131 :
132 0 : void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
133 0 : const MSAAQuadProcessor& qp = args.fGP.cast<MSAAQuadProcessor>();
134 0 : GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
135 0 : GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
136 0 : GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
137 :
138 : // emit attributes
139 0 : varyingHandler->emitAttributes(qp);
140 0 : varyingHandler->addPassThroughAttribute(qp.inColor(), args.fOutputColor);
141 :
142 0 : GrGLSLVertToFrag uv(kVec2f_GrSLType);
143 0 : varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision);
144 0 : vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qp.inUV()->fName);
145 :
146 : // Setup position
147 0 : this->setupPosition(vsBuilder, uniformHandler, gpArgs, qp.inPosition()->fName,
148 0 : qp.viewMatrix(), &fViewMatrixUniform);
149 :
150 : // emit transforms
151 0 : this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
152 0 : qp.inPosition()->fName, SkMatrix::I(),
153 0 : args.fFPCoordTransformHandler);
154 :
155 0 : GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
156 0 : fsBuilder->codeAppendf("if (%s.x * %s.x >= %s.y) discard;", uv.fsIn(), uv.fsIn(),
157 0 : uv.fsIn());
158 0 : fsBuilder->codeAppendf("%s = vec4(1.0);", args.fOutputCoverage);
159 0 : }
160 :
161 0 : static inline void GenKey(const GrGeometryProcessor& gp,
162 : const GrShaderCaps&,
163 : GrProcessorKeyBuilder* b) {
164 0 : const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
165 0 : uint32_t key = 0;
166 0 : key |= qp.viewMatrix().hasPerspective() ? 0x1 : 0x0;
167 0 : key |= qp.viewMatrix().isIdentity() ? 0x2: 0x0;
168 0 : b->add32(key);
169 0 : }
170 :
171 0 : void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp,
172 : FPCoordTransformIter&& transformIter) override {
173 0 : const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
174 0 : if (!qp.viewMatrix().isIdentity()) {
175 : float viewMatrix[3 * 3];
176 0 : GrGLSLGetMatrix<3>(viewMatrix, qp.viewMatrix());
177 0 : pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
178 : }
179 0 : this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
180 0 : }
181 :
182 : private:
183 : typedef GrGLSLGeometryProcessor INHERITED;
184 :
185 : UniformHandle fViewMatrixUniform;
186 : };
187 :
188 0 : virtual void getGLSLProcessorKey(const GrShaderCaps& caps,
189 : GrProcessorKeyBuilder* b) const override {
190 0 : GLSLProcessor::GenKey(*this, caps, b);
191 0 : }
192 :
193 0 : virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
194 0 : return new GLSLProcessor(*this);
195 : }
196 :
197 : private:
198 0 : MSAAQuadProcessor(const SkMatrix& viewMatrix)
199 0 : : fViewMatrix(viewMatrix) {
200 0 : this->initClassID<MSAAQuadProcessor>();
201 0 : fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
202 0 : kHigh_GrSLPrecision);
203 0 : fInUV = &this->addVertexAttrib("inUV", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision);
204 0 : fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
205 0 : this->setSampleShading(1.0f);
206 0 : }
207 :
208 : const Attribute* fInPosition;
209 : const Attribute* fInUV;
210 : const Attribute* fInColor;
211 : SkMatrix fViewMatrix;
212 :
213 : GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
214 :
215 : typedef GrGeometryProcessor INHERITED;
216 : };
217 :
218 0 : class MSAAPathOp final : public GrLegacyMeshDrawOp {
219 : public:
220 0 : DEFINE_OP_CLASS_ID
221 0 : static std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color, const SkPath& path,
222 : const SkMatrix& viewMatrix,
223 : const SkRect& devBounds) {
224 : int contourCount;
225 : int maxLineVertices;
226 : int maxQuadVertices;
227 : ComputeWorstCasePointCount(path, viewMatrix, &contourCount, &maxLineVertices,
228 0 : &maxQuadVertices);
229 0 : bool isIndexed = contourCount > 1;
230 0 : if (isIndexed &&
231 0 : (maxLineVertices > kMaxIndexedVertexCnt || maxQuadVertices > kMaxIndexedVertexCnt)) {
232 0 : return nullptr;
233 : }
234 :
235 : return std::unique_ptr<GrLegacyMeshDrawOp>(new MSAAPathOp(
236 0 : color, path, viewMatrix, devBounds, maxLineVertices, maxQuadVertices, isIndexed));
237 : }
238 :
239 0 : const char* name() const override { return "MSAAPathOp"; }
240 :
241 0 : SkString dumpInfo() const override {
242 0 : SkString string;
243 0 : string.appendf("Indexed: %d\n", fIsIndexed);
244 0 : for (const auto& path : fPaths) {
245 0 : string.appendf("Color: 0x%08x\n", path.fColor);
246 : }
247 0 : string.append(DumpPipelineInfo(*this->pipeline()));
248 0 : string.append(INHERITED::dumpInfo());
249 0 : return string;
250 : }
251 :
252 : private:
253 0 : MSAAPathOp(GrColor color, const SkPath& path, const SkMatrix& viewMatrix,
254 : const SkRect& devBounds, int maxLineVertices, int maxQuadVertices, bool isIndexed)
255 0 : : INHERITED(ClassID())
256 : , fViewMatrix(viewMatrix)
257 : , fMaxLineVertices(maxLineVertices)
258 : , fMaxQuadVertices(maxQuadVertices)
259 0 : , fIsIndexed(isIndexed) {
260 0 : fPaths.emplace_back(PathInfo{color, path});
261 0 : this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo);
262 0 : }
263 :
264 0 : void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
265 : GrProcessorAnalysisCoverage* coverage) const override {
266 0 : color->setToConstant(fPaths[0].fColor);
267 0 : *coverage = GrProcessorAnalysisCoverage::kNone;
268 0 : }
269 :
270 0 : void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override {
271 0 : optimizations.getOverrideColorIfSet(&fPaths[0].fColor);
272 0 : }
273 :
274 0 : static void ComputeWorstCasePointCount(const SkPath& path, const SkMatrix& m, int* subpaths,
275 : int* outLinePointCount, int* outQuadPointCount) {
276 0 : SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m, path.getBounds());
277 0 : int linePointCount = 0;
278 0 : int quadPointCount = 0;
279 0 : *subpaths = 1;
280 :
281 0 : bool first = true;
282 :
283 0 : SkPath::Iter iter(path, true);
284 : SkPath::Verb verb;
285 :
286 : SkPoint pts[4];
287 0 : while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
288 0 : switch (verb) {
289 : case SkPath::kLine_Verb:
290 0 : linePointCount += 1;
291 0 : break;
292 : case SkPath::kConic_Verb: {
293 0 : SkScalar weight = iter.conicWeight();
294 0 : SkAutoConicToQuads converter;
295 0 : converter.computeQuads(pts, weight, tolerance);
296 0 : int quadPts = converter.countQuads();
297 0 : linePointCount += quadPts;
298 0 : quadPointCount += 3 * quadPts;
299 : }
300 : case SkPath::kQuad_Verb:
301 0 : linePointCount += 1;
302 0 : quadPointCount += 3;
303 0 : break;
304 : case SkPath::kCubic_Verb: {
305 0 : SkSTArray<15, SkPoint, true> quadPts;
306 0 : GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts);
307 0 : int count = quadPts.count();
308 0 : linePointCount += count / 3;
309 0 : quadPointCount += count;
310 0 : break;
311 : }
312 : case SkPath::kMove_Verb:
313 0 : linePointCount += 1;
314 0 : if (!first) {
315 0 : ++(*subpaths);
316 : }
317 0 : break;
318 : default:
319 0 : break;
320 : }
321 0 : first = false;
322 : }
323 0 : *outLinePointCount = linePointCount;
324 0 : *outQuadPointCount = quadPointCount;
325 0 : }
326 :
327 0 : void onPrepareDraws(Target* target) const override {
328 0 : if (fMaxLineVertices == 0) {
329 0 : SkASSERT(fMaxQuadVertices == 0);
330 0 : return;
331 : }
332 :
333 0 : GrPrimitiveType primitiveType = fIsIndexed ? kTriangles_GrPrimitiveType
334 0 : : kTriangleFan_GrPrimitiveType;
335 :
336 : // allocate vertex / index buffers
337 : const GrBuffer* lineVertexBuffer;
338 : int firstLineVertex;
339 : MSAALineVertices lines;
340 0 : size_t lineVertexStride = sizeof(MSAALineVertices::Vertex);
341 0 : lines.vertices = (MSAALineVertices::Vertex*) target->makeVertexSpace(lineVertexStride,
342 0 : fMaxLineVertices,
343 : &lineVertexBuffer,
344 : &firstLineVertex);
345 0 : if (!lines.vertices) {
346 0 : SkDebugf("Could not allocate vertices\n");
347 0 : return;
348 : }
349 0 : lines.nextVertex = lines.vertices;
350 0 : SkDEBUGCODE(lines.verticesEnd = lines.vertices + fMaxLineVertices;)
351 :
352 : MSAAQuadVertices quads;
353 0 : size_t quadVertexStride = sizeof(MSAAQuadVertices::Vertex);
354 0 : SkAutoMalloc quadVertexPtr(fMaxQuadVertices * quadVertexStride);
355 0 : quads.vertices = (MSAAQuadVertices::Vertex*) quadVertexPtr.get();
356 0 : quads.nextVertex = quads.vertices;
357 0 : SkDEBUGCODE(quads.verticesEnd = quads.vertices + fMaxQuadVertices;)
358 :
359 0 : const GrBuffer* lineIndexBuffer = nullptr;
360 : int firstLineIndex;
361 0 : if (fIsIndexed) {
362 0 : lines.indices =
363 0 : target->makeIndexSpace(3 * fMaxLineVertices, &lineIndexBuffer, &firstLineIndex);
364 0 : if (!lines.indices) {
365 0 : SkDebugf("Could not allocate indices\n");
366 0 : return;
367 : }
368 0 : lines.nextIndex = lines.indices;
369 : } else {
370 0 : lines.indices = nullptr;
371 0 : lines.nextIndex = nullptr;
372 : }
373 :
374 0 : SkAutoFree quadIndexPtr;
375 0 : if (fIsIndexed) {
376 0 : quads.indices = (uint16_t*)sk_malloc_throw(3 * fMaxQuadVertices * sizeof(uint16_t));
377 0 : quadIndexPtr.reset(quads.indices);
378 0 : quads.nextIndex = quads.indices;
379 : } else {
380 0 : quads.indices = nullptr;
381 0 : quads.nextIndex = nullptr;
382 : }
383 :
384 : // fill buffers
385 0 : for (int i = 0; i < fPaths.count(); i++) {
386 0 : const PathInfo& pathInfo = fPaths[i];
387 :
388 0 : if (!this->createGeom(lines,
389 : quads,
390 : pathInfo.fPath,
391 : fViewMatrix,
392 0 : pathInfo.fColor,
393 0 : fIsIndexed)) {
394 0 : return;
395 : }
396 : }
397 0 : int lineVertexOffset = (int) (lines.nextVertex - lines.vertices);
398 0 : int lineIndexOffset = (int) (lines.nextIndex - lines.indices);
399 0 : SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= 3 * fMaxLineVertices);
400 0 : int quadVertexOffset = (int) (quads.nextVertex - quads.vertices);
401 0 : int quadIndexOffset = (int) (quads.nextIndex - quads.indices);
402 0 : SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= 3 * fMaxQuadVertices);
403 :
404 0 : if (lineVertexOffset) {
405 0 : sk_sp<GrGeometryProcessor> lineGP;
406 : {
407 : using namespace GrDefaultGeoProcFactory;
408 0 : lineGP = GrDefaultGeoProcFactory::Make(Color(Color::kPremulGrColorAttribute_Type),
409 : Coverage::kSolid_Type,
410 0 : LocalCoords(LocalCoords::kUnused_Type),
411 0 : fViewMatrix);
412 : }
413 0 : SkASSERT(lineVertexStride == lineGP->getVertexStride());
414 :
415 0 : GrMesh lineMeshes;
416 0 : if (fIsIndexed) {
417 : lineMeshes.initIndexed(primitiveType, lineVertexBuffer, lineIndexBuffer,
418 : firstLineVertex, firstLineIndex, lineVertexOffset,
419 0 : lineIndexOffset);
420 : } else {
421 : lineMeshes.init(primitiveType, lineVertexBuffer, firstLineVertex,
422 0 : lineVertexOffset);
423 : }
424 0 : target->draw(lineGP.get(), this->pipeline(), lineMeshes);
425 : }
426 :
427 0 : if (quadVertexOffset) {
428 0 : sk_sp<const GrGeometryProcessor> quadGP(MSAAQuadProcessor::Create(fViewMatrix));
429 0 : SkASSERT(quadVertexStride == quadGP->getVertexStride());
430 :
431 : const GrBuffer* quadVertexBuffer;
432 : int firstQuadVertex;
433 : MSAAQuadVertices::Vertex* quadVertices = (MSAAQuadVertices::Vertex*)
434 : target->makeVertexSpace(quadVertexStride, quadVertexOffset, &quadVertexBuffer,
435 0 : &firstQuadVertex);
436 0 : memcpy(quadVertices, quads.vertices, quadVertexStride * quadVertexOffset);
437 0 : GrMesh quadMeshes;
438 0 : if (fIsIndexed) {
439 : const GrBuffer* quadIndexBuffer;
440 : int firstQuadIndex;
441 : uint16_t* quadIndices = (uint16_t*) target->makeIndexSpace(quadIndexOffset,
442 : &quadIndexBuffer,
443 0 : &firstQuadIndex);
444 0 : memcpy(quadIndices, quads.indices, sizeof(uint16_t) * quadIndexOffset);
445 : quadMeshes.initIndexed(kTriangles_GrPrimitiveType, quadVertexBuffer,
446 : quadIndexBuffer, firstQuadVertex, firstQuadIndex,
447 0 : quadVertexOffset, quadIndexOffset);
448 : } else {
449 : quadMeshes.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex,
450 0 : quadVertexOffset);
451 : }
452 0 : target->draw(quadGP.get(), this->pipeline(), quadMeshes);
453 : }
454 : }
455 :
456 0 : bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
457 0 : MSAAPathOp* that = t->cast<MSAAPathOp>();
458 0 : if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
459 : that->bounds(), caps)) {
460 0 : return false;
461 : }
462 :
463 0 : if (this->bounds().intersects(that->bounds())) {
464 0 : return false;
465 : }
466 :
467 0 : if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
468 0 : return false;
469 : }
470 :
471 : // If we grow to include 2+ paths we will be indexed.
472 0 : if (((fMaxLineVertices + that->fMaxLineVertices) > kMaxIndexedVertexCnt) ||
473 0 : ((fMaxQuadVertices + that->fMaxQuadVertices) > kMaxIndexedVertexCnt)) {
474 0 : return false;
475 : }
476 :
477 0 : fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
478 0 : this->joinBounds(*that);
479 0 : fIsIndexed = true;
480 0 : fMaxLineVertices += that->fMaxLineVertices;
481 0 : fMaxQuadVertices += that->fMaxQuadVertices;
482 0 : return true;
483 : }
484 :
485 0 : bool createGeom(MSAALineVertices& lines,
486 : MSAAQuadVertices& quads,
487 : const SkPath& path,
488 : const SkMatrix& m,
489 : SkColor color,
490 : bool isIndexed) const {
491 : {
492 0 : const SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m,
493 0 : path.getBounds());
494 0 : uint16_t subpathIdxStart = (uint16_t) (lines.nextVertex - lines.vertices);
495 :
496 : SkPoint pts[4];
497 :
498 0 : bool first = true;
499 0 : SkPath::Iter iter(path, true);
500 :
501 0 : bool done = false;
502 0 : while (!done) {
503 0 : SkPath::Verb verb = iter.next(pts);
504 0 : switch (verb) {
505 : case SkPath::kMove_Verb:
506 0 : if (!first) {
507 0 : uint16_t currIdx = (uint16_t) (lines.nextVertex - lines.vertices);
508 0 : subpathIdxStart = currIdx;
509 : }
510 0 : SkASSERT(lines.nextVertex < lines.verticesEnd);
511 0 : *(lines.nextVertex++) = { pts[0], color };
512 0 : break;
513 : case SkPath::kLine_Verb:
514 0 : if (isIndexed) {
515 0 : uint16_t prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
516 0 : if (prevIdx > subpathIdxStart) {
517 0 : append_contour_edge_indices(subpathIdxStart, prevIdx, lines);
518 : }
519 : }
520 0 : SkASSERT(lines.nextVertex < lines.verticesEnd);
521 0 : *(lines.nextVertex++) = { pts[1], color };
522 0 : break;
523 : case SkPath::kConic_Verb: {
524 0 : SkScalar weight = iter.conicWeight();
525 0 : SkAutoConicToQuads converter;
526 0 : const SkPoint* quadPts = converter.computeQuads(pts, weight, tolerance);
527 0 : for (int i = 0; i < converter.countQuads(); ++i) {
528 0 : add_quad(lines, quads, quadPts + i * 2, color, isIndexed,
529 0 : subpathIdxStart);
530 : }
531 0 : break;
532 : }
533 : case SkPath::kQuad_Verb: {
534 0 : add_quad(lines, quads, pts, color, isIndexed, subpathIdxStart);
535 0 : break;
536 : }
537 : case SkPath::kCubic_Verb: {
538 0 : SkSTArray<15, SkPoint, true> quadPts;
539 0 : GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts);
540 0 : int count = quadPts.count();
541 0 : for (int i = 0; i < count; i += 3) {
542 0 : add_quad(lines, quads, &quadPts[i], color, isIndexed, subpathIdxStart);
543 : }
544 0 : break;
545 : }
546 : case SkPath::kClose_Verb:
547 0 : break;
548 : case SkPath::kDone_Verb:
549 0 : done = true;
550 : }
551 0 : first = false;
552 : }
553 : }
554 0 : return true;
555 : }
556 :
557 : // Lines and quads may render with an index buffer. However, we don't have any support for
558 : // overflowing the max index.
559 : static constexpr int kMaxIndexedVertexCnt = SK_MaxU16 / 3;
560 0 : struct PathInfo {
561 : GrColor fColor;
562 : SkPath fPath;
563 : };
564 :
565 : SkSTArray<1, PathInfo, true> fPaths;
566 :
567 : SkMatrix fViewMatrix;
568 : int fMaxLineVertices;
569 : int fMaxQuadVertices;
570 : bool fIsIndexed;
571 :
572 : typedef GrLegacyMeshDrawOp INHERITED;
573 : };
574 :
575 0 : bool GrMSAAPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext,
576 : GrPaint&& paint,
577 : GrAAType aaType,
578 : const GrUserStencilSettings& userStencilSettings,
579 : const GrClip& clip,
580 : const SkMatrix& viewMatrix,
581 : const GrShape& shape,
582 : bool stencilOnly) {
583 0 : SkASSERT(shape.style().isSimpleFill());
584 0 : SkPath path;
585 0 : shape.asPath(&path);
586 :
587 0 : const GrUserStencilSettings* passes[2] = {nullptr, nullptr};
588 0 : bool reverse = false;
589 :
590 0 : if (single_pass_shape(shape)) {
591 0 : if (stencilOnly) {
592 0 : passes[0] = &gDirectToStencil;
593 : } else {
594 0 : passes[0] = &userStencilSettings;
595 : }
596 : } else {
597 0 : switch (path.getFillType()) {
598 : case SkPath::kInverseEvenOdd_FillType:
599 0 : reverse = true;
600 : // fallthrough
601 : case SkPath::kEvenOdd_FillType:
602 0 : passes[0] = &gEOStencilPass;
603 0 : if (!stencilOnly) {
604 0 : passes[1] = reverse ? &gInvEOColorPass : &gEOColorPass;
605 : }
606 0 : break;
607 :
608 : case SkPath::kInverseWinding_FillType:
609 0 : reverse = true;
610 : // fallthrough
611 : case SkPath::kWinding_FillType:
612 0 : passes[0] = &gWindStencilSeparateWithWrap;
613 0 : if (!stencilOnly) {
614 0 : passes[1] = reverse ? &gInvWindColorPass : &gWindColorPass;
615 : }
616 0 : break;
617 : default:
618 0 : SkDEBUGFAIL("Unknown path fFill!");
619 0 : return false;
620 : }
621 : }
622 :
623 : SkRect devBounds;
624 0 : GetPathDevBounds(path, renderTargetContext->width(), renderTargetContext->height(), viewMatrix,
625 0 : &devBounds);
626 :
627 0 : SkASSERT(passes[0]);
628 : { // First pass
629 : std::unique_ptr<GrLegacyMeshDrawOp> op =
630 0 : MSAAPathOp::Make(paint.getColor(), path, viewMatrix, devBounds);
631 0 : if (!op) {
632 0 : return false;
633 : }
634 0 : bool firstPassIsStencil = stencilOnly || passes[1];
635 : // If we have a cover pass then we ignore the paint in the first pass and apply it in the
636 : // second.
637 0 : GrPaint::MoveOrNew firstPassPaint(paint, firstPassIsStencil);
638 0 : if (firstPassIsStencil) {
639 0 : firstPassPaint.paint().setXPFactory(GrDisableColorXPFactory::Get());
640 : }
641 0 : GrPipelineBuilder pipelineBuilder(std::move(firstPassPaint), aaType);
642 0 : pipelineBuilder.setUserStencil(passes[0]);
643 0 : renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
644 : }
645 :
646 0 : if (passes[1]) {
647 : SkRect bounds;
648 0 : SkMatrix localMatrix = SkMatrix::I();
649 0 : if (reverse) {
650 : // draw over the dev bounds (which will be the whole dst surface for inv fill).
651 0 : bounds = devBounds;
652 : SkMatrix vmi;
653 : // mapRect through persp matrix may not be correct
654 0 : if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
655 0 : vmi.mapRect(&bounds);
656 : } else {
657 0 : if (!viewMatrix.invert(&localMatrix)) {
658 0 : return false;
659 : }
660 : }
661 : } else {
662 0 : bounds = path.getBounds();
663 : }
664 : const SkMatrix& viewM =
665 0 : (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix;
666 : std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
667 0 : paint.getColor(), viewM, bounds, nullptr, &localMatrix));
668 :
669 0 : GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
670 0 : pipelineBuilder.setUserStencil(passes[1]);
671 :
672 0 : renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
673 : }
674 0 : return true;
675 : }
676 :
677 0 : bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
678 : // This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are
679 : // handled by passing on the original shape and letting the caller compute the stroked shape
680 : // which will have a fill style.
681 0 : return args.fShape->style().isSimpleFill() && (GrAAType::kCoverage != args.fAAType);
682 : }
683 :
684 0 : bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
685 0 : GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
686 : "GrMSAAPathRenderer::onDrawPath");
687 0 : SkTLazy<GrShape> tmpShape;
688 0 : const GrShape* shape = args.fShape;
689 0 : if (shape->style().applies()) {
690 0 : SkScalar styleScale = GrStyle::MatrixToScaleFactor(*args.fViewMatrix);
691 0 : tmpShape.init(args.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale));
692 0 : shape = tmpShape.get();
693 : }
694 0 : return this->internalDrawPath(args.fRenderTargetContext,
695 0 : std::move(args.fPaint),
696 0 : args.fAAType,
697 0 : *args.fUserStencilSettings,
698 0 : *args.fClip,
699 0 : *args.fViewMatrix,
700 : *shape,
701 0 : false);
702 : }
703 :
704 0 : void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) {
705 0 : GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
706 : "GrMSAAPathRenderer::onStencilPath");
707 0 : SkASSERT(args.fShape->style().isSimpleFill());
708 0 : SkASSERT(!args.fShape->mayBeInverseFilledAfterStyling());
709 :
710 0 : GrPaint paint;
711 0 : paint.setXPFactory(GrDisableColorXPFactory::Get());
712 :
713 0 : this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType,
714 0 : GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix,
715 0 : *args.fShape, true);
716 0 : }
717 :
718 : ///////////////////////////////////////////////////////////////////////////////////////////////////
|