LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/ops - GrMSAAPathRenderer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 364 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 41 0.0 %
Legend: Lines: hit not hit

          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             : ///////////////////////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.13