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

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 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 "GrAALinearizingConvexPathRenderer.h"
       9             : 
      10             : #include "GrAAConvexTessellator.h"
      11             : #include "GrContext.h"
      12             : #include "GrDefaultGeoProcFactory.h"
      13             : #include "GrDrawOpTest.h"
      14             : #include "GrGeometryProcessor.h"
      15             : #include "GrOpFlushState.h"
      16             : #include "GrPathUtils.h"
      17             : #include "GrPipelineBuilder.h"
      18             : #include "GrProcessor.h"
      19             : #include "GrStyle.h"
      20             : #include "SkGeometry.h"
      21             : #include "SkPathPriv.h"
      22             : #include "SkString.h"
      23             : #include "SkTraceEvent.h"
      24             : #include "glsl/GrGLSLGeometryProcessor.h"
      25             : #include "ops/GrMeshDrawOp.h"
      26             : 
      27             : static const int DEFAULT_BUFFER_SIZE = 100;
      28             : 
      29             : // The thicker the stroke, the harder it is to produce high-quality results using tessellation. For
      30             : // the time being, we simply drop back to software rendering above this stroke width.
      31             : static const SkScalar kMaxStrokeWidth = 20.0;
      32             : 
      33           0 : GrAALinearizingConvexPathRenderer::GrAALinearizingConvexPathRenderer() {
      34           0 : }
      35             : 
      36             : ///////////////////////////////////////////////////////////////////////////////
      37             : 
      38           0 : bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
      39           0 :     if (GrAAType::kCoverage != args.fAAType) {
      40           0 :         return false;
      41             :     }
      42           0 :     if (!args.fShape->knownToBeConvex()) {
      43           0 :         return false;
      44             :     }
      45           0 :     if (args.fShape->style().pathEffect()) {
      46           0 :         return false;
      47             :     }
      48           0 :     if (args.fShape->inverseFilled()) {
      49           0 :         return false;
      50             :     }
      51           0 :     const SkStrokeRec& stroke = args.fShape->style().strokeRec();
      52             : 
      53           0 :     if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
      54           0 :         stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
      55           0 :         if (!args.fViewMatrix->isSimilarity()) {
      56           0 :             return false;
      57             :         }
      58           0 :         SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
      59           0 :         if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) {
      60           0 :             return false;
      61             :         }
      62           0 :         return strokeWidth <= kMaxStrokeWidth &&
      63           0 :                args.fShape->knownToBeClosed() &&
      64           0 :                stroke.getJoin() != SkPaint::Join::kRound_Join;
      65             :     }
      66           0 :     return stroke.getStyle() == SkStrokeRec::kFill_Style;
      67             : }
      68             : 
      69             : // extract the result vertices and indices from the GrAAConvexTessellator
      70           0 : static void extract_verts(const GrAAConvexTessellator& tess,
      71             :                           void* vertices,
      72             :                           size_t vertexStride,
      73             :                           GrColor color,
      74             :                           uint16_t firstIndex,
      75             :                           uint16_t* idxs,
      76             :                           bool tweakAlphaForCoverage) {
      77           0 :     intptr_t verts = reinterpret_cast<intptr_t>(vertices);
      78             : 
      79           0 :     for (int i = 0; i < tess.numPts(); ++i) {
      80           0 :         *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i);
      81             :     }
      82             : 
      83             :     // Make 'verts' point to the colors
      84           0 :     verts += sizeof(SkPoint);
      85           0 :     for (int i = 0; i < tess.numPts(); ++i) {
      86           0 :         if (tweakAlphaForCoverage) {
      87           0 :             SkASSERT(SkScalarRoundToInt(255.0f * tess.coverage(i)) <= 255);
      88           0 :             unsigned scale = SkScalarRoundToInt(255.0f * tess.coverage(i));
      89           0 :             GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
      90           0 :             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
      91             :         } else {
      92           0 :             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
      93           0 :             *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
      94           0 :                     tess.coverage(i);
      95             :         }
      96             :     }
      97             : 
      98           0 :     for (int i = 0; i < tess.numIndices(); ++i) {
      99           0 :         idxs[i] = tess.index(i) + firstIndex;
     100             :     }
     101           0 : }
     102             : 
     103           0 : static sk_sp<GrGeometryProcessor> create_fill_gp(bool tweakAlphaForCoverage,
     104             :                                                  const SkMatrix& viewMatrix,
     105             :                                                  bool usesLocalCoords) {
     106             :     using namespace GrDefaultGeoProcFactory;
     107             : 
     108             :     Coverage::Type coverageType;
     109           0 :     if (tweakAlphaForCoverage) {
     110           0 :         coverageType = Coverage::kSolid_Type;
     111             :     } else {
     112           0 :         coverageType = Coverage::kAttribute_Type;
     113             :     }
     114             :     LocalCoords::Type localCoordsType =
     115           0 :             usesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type;
     116             :     return MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type, coverageType, localCoordsType,
     117           0 :                               viewMatrix);
     118             : }
     119             : 
     120           0 : class AAFlatteningConvexPathOp final : public GrLegacyMeshDrawOp {
     121             : public:
     122           0 :     DEFINE_OP_CLASS_ID
     123           0 :     static std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
     124             :                                                     const SkMatrix& viewMatrix,
     125             :                                                     const SkPath& path,
     126             :                                                     SkScalar strokeWidth,
     127             :                                                     SkStrokeRec::Style style,
     128             :                                                     SkPaint::Join join,
     129             :                                                     SkScalar miterLimit) {
     130             :         return std::unique_ptr<GrLegacyMeshDrawOp>(new AAFlatteningConvexPathOp(
     131           0 :                 color, viewMatrix, path, strokeWidth, style, join, miterLimit));
     132             :     }
     133             : 
     134           0 :     const char* name() const override { return "AAFlatteningConvexPathOp"; }
     135             : 
     136           0 :     SkString dumpInfo() const override {
     137           0 :         SkString string;
     138           0 :         for (const auto& path : fPaths) {
     139           0 :             string.appendf(
     140             :                     "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, "
     141             :                     "MiterLimit: %.2f\n",
     142           0 :                     path.fColor, path.fStrokeWidth, path.fStyle, path.fJoin, path.fMiterLimit);
     143             :         }
     144           0 :         string.append(DumpPipelineInfo(*this->pipeline()));
     145           0 :         string.append(INHERITED::dumpInfo());
     146           0 :         return string;
     147             :     }
     148             : 
     149             : private:
     150           0 :     AAFlatteningConvexPathOp(GrColor color,
     151             :                              const SkMatrix& viewMatrix,
     152             :                              const SkPath& path,
     153             :                              SkScalar strokeWidth,
     154             :                              SkStrokeRec::Style style,
     155             :                              SkPaint::Join join,
     156             :                              SkScalar miterLimit)
     157           0 :             : INHERITED(ClassID()) {
     158             :         fPaths.emplace_back(
     159           0 :                 PathData{color, viewMatrix, path, strokeWidth, style, join, miterLimit});
     160             : 
     161             :         // compute bounds
     162           0 :         SkRect bounds = path.getBounds();
     163           0 :         SkScalar w = strokeWidth;
     164           0 :         if (w > 0) {
     165           0 :             w /= 2;
     166             :             // If the half stroke width is < 1 then we effectively fallback to bevel joins.
     167           0 :             if (SkPaint::kMiter_Join == join && w > 1.f) {
     168           0 :                 w *= miterLimit;
     169             :             }
     170           0 :             bounds.outset(w, w);
     171             :         }
     172           0 :         this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kYes, IsZeroArea::kNo);
     173           0 :     }
     174             : 
     175           0 :     void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
     176             :                                     GrProcessorAnalysisCoverage* coverage) const override {
     177           0 :         color->setToConstant(fPaths[0].fColor);
     178           0 :         *coverage = GrProcessorAnalysisCoverage::kSingleChannel;
     179           0 :     }
     180             : 
     181           0 :     void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override {
     182           0 :         optimizations.getOverrideColorIfSet(&fPaths[0].fColor);
     183           0 :         fUsesLocalCoords = optimizations.readsLocalCoords();
     184           0 :         fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage();
     185           0 :     }
     186             : 
     187           0 :     void draw(GrLegacyMeshDrawOp::Target* target, const GrGeometryProcessor* gp, int vertexCount,
     188             :               size_t vertexStride, void* vertices, int indexCount, uint16_t* indices) const {
     189           0 :         if (vertexCount == 0 || indexCount == 0) {
     190           0 :             return;
     191             :         }
     192             :         const GrBuffer* vertexBuffer;
     193           0 :         GrMesh mesh;
     194             :         int firstVertex;
     195             :         void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
     196           0 :                                               &firstVertex);
     197           0 :         if (!verts) {
     198           0 :             SkDebugf("Could not allocate vertices\n");
     199           0 :             return;
     200             :         }
     201           0 :         memcpy(verts, vertices, vertexCount * vertexStride);
     202             : 
     203             :         const GrBuffer* indexBuffer;
     204             :         int firstIndex;
     205           0 :         uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
     206           0 :         if (!idxs) {
     207           0 :             SkDebugf("Could not allocate indices\n");
     208           0 :             return;
     209             :         }
     210           0 :         memcpy(idxs, indices, indexCount * sizeof(uint16_t));
     211             :         mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex,
     212           0 :                          firstIndex, vertexCount, indexCount);
     213           0 :         target->draw(gp, this->pipeline(), mesh);
     214             :     }
     215             : 
     216           0 :     void onPrepareDraws(Target* target) const override {
     217           0 :         bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
     218             : 
     219             :         // Setup GrGeometryProcessor
     220             :         sk_sp<GrGeometryProcessor> gp(create_fill_gp(
     221           0 :                 canTweakAlphaForCoverage, this->viewMatrix(), this->usesLocalCoords()));
     222           0 :         if (!gp) {
     223           0 :             SkDebugf("Couldn't create a GrGeometryProcessor\n");
     224           0 :             return;
     225             :         }
     226             : 
     227           0 :         size_t vertexStride = gp->getVertexStride();
     228             : 
     229           0 :         SkASSERT(canTweakAlphaForCoverage ?
     230             :                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
     231             :                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
     232             : 
     233           0 :         int instanceCount = fPaths.count();
     234             : 
     235           0 :         int vertexCount = 0;
     236           0 :         int indexCount = 0;
     237           0 :         int maxVertices = DEFAULT_BUFFER_SIZE;
     238           0 :         int maxIndices = DEFAULT_BUFFER_SIZE;
     239           0 :         uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride);
     240           0 :         uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t));
     241           0 :         for (int i = 0; i < instanceCount; i++) {
     242           0 :             const PathData& args = fPaths[i];
     243           0 :             GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth,
     244           0 :                                        args.fJoin, args.fMiterLimit);
     245             : 
     246           0 :             if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
     247           0 :                 continue;
     248             :             }
     249             : 
     250           0 :             int currentIndices = tess.numIndices();
     251           0 :             SkASSERT(currentIndices <= UINT16_MAX);
     252           0 :             if (indexCount + currentIndices > UINT16_MAX) {
     253             :                 // if we added the current instance, we would overflow the indices we can store in a
     254             :                 // uint16_t. Draw what we've got so far and reset.
     255           0 :                 this->draw(target, gp.get(),
     256           0 :                            vertexCount, vertexStride, vertices, indexCount, indices);
     257           0 :                 vertexCount = 0;
     258           0 :                 indexCount = 0;
     259             :             }
     260           0 :             int currentVertices = tess.numPts();
     261           0 :             if (vertexCount + currentVertices > maxVertices) {
     262           0 :                 maxVertices = SkTMax(vertexCount + currentVertices, maxVertices * 2);
     263           0 :                 vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride);
     264             :             }
     265           0 :             if (indexCount + currentIndices > maxIndices) {
     266           0 :                 maxIndices = SkTMax(indexCount + currentIndices, maxIndices * 2);
     267           0 :                 indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
     268             :             }
     269             : 
     270           0 :             extract_verts(tess, vertices + vertexStride * vertexCount, vertexStride, args.fColor,
     271           0 :                     vertexCount, indices + indexCount, canTweakAlphaForCoverage);
     272           0 :             vertexCount += currentVertices;
     273           0 :             indexCount += currentIndices;
     274             :         }
     275           0 :         this->draw(target, gp.get(), vertexCount, vertexStride, vertices, indexCount, indices);
     276           0 :         sk_free(vertices);
     277           0 :         sk_free(indices);
     278             :     }
     279             : 
     280           0 :     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
     281           0 :         AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
     282           0 :         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
     283             :                                     that->bounds(), caps)) {
     284           0 :             return false;
     285             :         }
     286             : 
     287           0 :         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
     288           0 :         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
     289           0 :             return false;
     290             :         }
     291             : 
     292             :         // In the event of two ops, one who can tweak, one who cannot, we just fall back to not
     293             :         // tweaking
     294           0 :         if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
     295           0 :             fCanTweakAlphaForCoverage = false;
     296             :         }
     297             : 
     298           0 :         fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
     299           0 :         this->joinBounds(*that);
     300           0 :         return true;
     301             :     }
     302             : 
     303           0 :     bool usesLocalCoords() const { return fUsesLocalCoords; }
     304           0 :     bool canTweakAlphaForCoverage() const { return fCanTweakAlphaForCoverage; }
     305           0 :     const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }
     306             : 
     307           0 :     struct PathData {
     308             :         GrColor fColor;
     309             :         SkMatrix fViewMatrix;
     310             :         SkPath fPath;
     311             :         SkScalar fStrokeWidth;
     312             :         SkStrokeRec::Style fStyle;
     313             :         SkPaint::Join fJoin;
     314             :         SkScalar fMiterLimit;
     315             :     };
     316             : 
     317             :     bool fUsesLocalCoords;
     318             :     bool fCanTweakAlphaForCoverage;
     319             :     SkSTArray<1, PathData, true> fPaths;
     320             : 
     321             :     typedef GrLegacyMeshDrawOp INHERITED;
     322             : };
     323             : 
     324           0 : bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
     325           0 :     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
     326             :                               "GrAALinearizingConvexPathRenderer::onDrawPath");
     327           0 :     SkASSERT(!args.fRenderTargetContext->isUnifiedMultisampled());
     328           0 :     SkASSERT(!args.fShape->isEmpty());
     329           0 :     SkASSERT(!args.fShape->style().pathEffect());
     330             : 
     331           0 :     SkPath path;
     332           0 :     args.fShape->asPath(&path);
     333           0 :     bool fill = args.fShape->style().isSimpleFill();
     334           0 :     const SkStrokeRec& stroke = args.fShape->style().strokeRec();
     335           0 :     SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth();
     336           0 :     SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin();
     337           0 :     SkScalar miterLimit = stroke.getMiter();
     338             : 
     339             :     std::unique_ptr<GrLegacyMeshDrawOp> op =
     340           0 :             AAFlatteningConvexPathOp::Make(args.fPaint.getColor(), *args.fViewMatrix, path,
     341           0 :                                            strokeWidth, stroke.getStyle(), join, miterLimit);
     342             : 
     343           0 :     GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType);
     344           0 :     pipelineBuilder.setUserStencil(args.fUserStencilSettings);
     345             : 
     346           0 :     args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip,
     347           0 :                                                    std::move(op));
     348             : 
     349           0 :     return true;
     350             : }
     351             : 
     352             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     353             : 
     354             : #if GR_TEST_UTILS
     355             : 
     356           0 : DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) {
     357           0 :     GrColor color = GrRandomColor(random);
     358           0 :     SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
     359           0 :     SkPath path = GrTest::TestPathConvex(random);
     360             : 
     361             :     SkStrokeRec::Style styles[3] = { SkStrokeRec::kFill_Style,
     362             :                                      SkStrokeRec::kStroke_Style,
     363           0 :                                      SkStrokeRec::kStrokeAndFill_Style };
     364             : 
     365           0 :     SkStrokeRec::Style style = styles[random->nextU() % 3];
     366             : 
     367           0 :     SkScalar strokeWidth = -1.f;
     368           0 :     SkPaint::Join join = SkPaint::kMiter_Join;
     369           0 :     SkScalar miterLimit = 0.5f;
     370             : 
     371           0 :     if (SkStrokeRec::kFill_Style != style) {
     372           0 :         strokeWidth = random->nextRangeF(1.0f, 10.0f);
     373           0 :         if (random->nextBool()) {
     374           0 :             join = SkPaint::kMiter_Join;
     375             :         } else {
     376           0 :             join = SkPaint::kBevel_Join;
     377             :         }
     378           0 :         miterLimit = random->nextRangeF(0.5f, 2.0f);
     379             :     }
     380             : 
     381             :     return AAFlatteningConvexPathOp::Make(color, viewMatrix, path, strokeWidth, style, join,
     382           0 :                                           miterLimit);
     383             : }
     384             : 
     385             : #endif

Generated by: LCOV version 1.13