LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/ops - GrTessellatingPathRenderer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 197 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 33 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 "GrTessellatingPathRenderer.h"
       9             : 
      10             : #include "GrAuditTrail.h"
      11             : #include "GrClip.h"
      12             : #include "GrDefaultGeoProcFactory.h"
      13             : #include "GrDrawOpTest.h"
      14             : #include "GrMesh.h"
      15             : #include "GrOpFlushState.h"
      16             : #include "GrPathUtils.h"
      17             : #include "GrPipelineBuilder.h"
      18             : #include "GrResourceCache.h"
      19             : #include "GrResourceProvider.h"
      20             : #include "GrTessellator.h"
      21             : #include "SkGeometry.h"
      22             : 
      23             : #include "ops/GrMeshDrawOp.h"
      24             : 
      25             : #include <stdio.h>
      26             : 
      27             : /*
      28             :  * This path renderer tessellates the path into triangles using GrTessellator, uploads the
      29             :  * triangles to a vertex buffer, and renders them with a single draw call. It can do screenspace
      30             :  * antialiasing with a one-pixel coverage ramp.
      31             :  */
      32             : namespace {
      33             : 
      34             : struct TessInfo {
      35             :     SkScalar  fTolerance;
      36             :     int       fCount;
      37             : };
      38             : 
      39             : // When the SkPathRef genID changes, invalidate a corresponding GrResource described by key.
      40             : class PathInvalidator : public SkPathRef::GenIDChangeListener {
      41             : public:
      42             :     explicit PathInvalidator(const GrUniqueKey& key) : fMsg(key) {}
      43             : private:
      44             :     GrUniqueKeyInvalidatedMessage fMsg;
      45             : 
      46             :     void onChange() override {
      47             :         SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
      48             :     }
      49             : };
      50             : 
      51           0 : bool cache_match(GrBuffer* vertexBuffer, SkScalar tol, int* actualCount) {
      52           0 :     if (!vertexBuffer) {
      53           0 :         return false;
      54             :     }
      55           0 :     const SkData* data = vertexBuffer->getUniqueKey().getCustomData();
      56           0 :     SkASSERT(data);
      57           0 :     const TessInfo* info = static_cast<const TessInfo*>(data->data());
      58           0 :     if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) {
      59           0 :         *actualCount = info->fCount;
      60           0 :         return true;
      61             :     }
      62           0 :     return false;
      63             : }
      64             : 
      65           0 : class StaticVertexAllocator : public GrTessellator::VertexAllocator {
      66             : public:
      67           0 :     StaticVertexAllocator(size_t stride, GrResourceProvider* resourceProvider, bool canMapVB)
      68           0 :       : VertexAllocator(stride)
      69             :       , fResourceProvider(resourceProvider)
      70             :       , fCanMapVB(canMapVB)
      71           0 :       , fVertices(nullptr) {
      72           0 :     }
      73           0 :     void* lock(int vertexCount) override {
      74           0 :         size_t size = vertexCount * stride();
      75           0 :         fVertexBuffer.reset(fResourceProvider->createBuffer(
      76           0 :             size, kVertex_GrBufferType, kStatic_GrAccessPattern, 0));
      77           0 :         if (!fVertexBuffer.get()) {
      78           0 :             return nullptr;
      79             :         }
      80           0 :         if (fCanMapVB) {
      81           0 :             fVertices = fVertexBuffer->map();
      82             :         } else {
      83           0 :             fVertices = sk_malloc_throw(vertexCount * stride());
      84             :         }
      85           0 :         return fVertices;
      86             :     }
      87           0 :     void unlock(int actualCount) override {
      88           0 :         if (fCanMapVB) {
      89           0 :             fVertexBuffer->unmap();
      90             :         } else {
      91           0 :             fVertexBuffer->updateData(fVertices, actualCount * stride());
      92           0 :             sk_free(fVertices);
      93             :         }
      94           0 :         fVertices = nullptr;
      95           0 :     }
      96           0 :     GrBuffer* vertexBuffer() { return fVertexBuffer.get(); }
      97             : private:
      98             :     sk_sp<GrBuffer> fVertexBuffer;
      99             :     GrResourceProvider* fResourceProvider;
     100             :     bool fCanMapVB;
     101             :     void* fVertices;
     102             : };
     103             : 
     104           0 : class DynamicVertexAllocator : public GrTessellator::VertexAllocator {
     105             : public:
     106           0 :     DynamicVertexAllocator(size_t stride, GrLegacyMeshDrawOp::Target* target)
     107           0 :             : VertexAllocator(stride)
     108             :             , fTarget(target)
     109             :             , fVertexBuffer(nullptr)
     110           0 :             , fVertices(nullptr) {}
     111           0 :     void* lock(int vertexCount) override {
     112           0 :         fVertexCount = vertexCount;
     113           0 :         fVertices = fTarget->makeVertexSpace(stride(), vertexCount, &fVertexBuffer, &fFirstVertex);
     114           0 :         return fVertices;
     115             :     }
     116           0 :     void unlock(int actualCount) override {
     117           0 :         fTarget->putBackVertices(fVertexCount - actualCount, stride());
     118           0 :         fVertices = nullptr;
     119           0 :     }
     120           0 :     const GrBuffer* vertexBuffer() const { return fVertexBuffer; }
     121           0 :     int firstVertex() const { return fFirstVertex; }
     122             : private:
     123             :     GrLegacyMeshDrawOp::Target* fTarget;
     124             :     const GrBuffer* fVertexBuffer;
     125             :     int fVertexCount;
     126             :     int fFirstVertex;
     127             :     void* fVertices;
     128             : };
     129             : 
     130             : }  // namespace
     131             : 
     132           0 : GrTessellatingPathRenderer::GrTessellatingPathRenderer() {
     133           0 : }
     134             : 
     135           0 : bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     136             :     // This path renderer can draw fill styles, and can do screenspace antialiasing via a
     137             :     // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
     138             :     // ones to simpler algorithms. We pass on paths that have styles, though they may come back
     139             :     // around after applying the styling information to the geometry to create a filled path. In
     140             :     // the non-AA case, We skip paths thta don't have a key since the real advantage of this path
     141             :     // renderer comes from caching the tessellated geometry. In the AA case, we do not cache, so we
     142             :     // accept paths without keys.
     143           0 :     if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
     144           0 :         return false;
     145             :     }
     146           0 :     if (GrAAType::kCoverage == args.fAAType) {
     147             : #ifdef SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER
     148           0 :         return false;
     149             : #else
     150             :         SkPath path;
     151             :         args.fShape->asPath(&path);
     152             :         if (path.countVerbs() > 10) {
     153             :             return false;
     154             :         }
     155             : #endif
     156           0 :     } else if (!args.fShape->hasUnstyledKey()) {
     157           0 :         return false;
     158             :     }
     159           0 :     return true;
     160             : }
     161             : 
     162           0 : class TessellatingPathOp final : public GrLegacyMeshDrawOp {
     163             : public:
     164           0 :     DEFINE_OP_CLASS_ID
     165             : 
     166           0 :     static std::unique_ptr<GrLegacyMeshDrawOp> Make(const GrColor& color,
     167             :                                                     const GrShape& shape,
     168             :                                                     const SkMatrix& viewMatrix,
     169             :                                                     SkIRect devClipBounds,
     170             :                                                     bool antiAlias) {
     171             :         return std::unique_ptr<GrLegacyMeshDrawOp>(
     172           0 :                 new TessellatingPathOp(color, shape, viewMatrix, devClipBounds, antiAlias));
     173             :     }
     174             : 
     175           0 :     const char* name() const override { return "TessellatingPathOp"; }
     176             : 
     177           0 :     SkString dumpInfo() const override {
     178           0 :         SkString string;
     179           0 :         string.appendf("Color 0x%08x, aa: %d\n", fColor, fAntiAlias);
     180           0 :         string.append(DumpPipelineInfo(*this->pipeline()));
     181           0 :         string.append(INHERITED::dumpInfo());
     182           0 :         return string;
     183             :     }
     184             : 
     185             : private:
     186           0 :     void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
     187             :                                     GrProcessorAnalysisCoverage* coverage) const override {
     188           0 :         color->setToConstant(fColor);
     189           0 :         *coverage = GrProcessorAnalysisCoverage::kSingleChannel;
     190           0 :     }
     191             : 
     192           0 :     void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override {
     193           0 :         optimizations.getOverrideColorIfSet(&fColor);
     194           0 :         fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage();
     195           0 :         fNeedsLocalCoords = optimizations.readsLocalCoords();
     196           0 :     }
     197             : 
     198           0 :     SkPath getPath() const {
     199           0 :         SkASSERT(!fShape.style().applies());
     200           0 :         SkPath path;
     201           0 :         fShape.asPath(&path);
     202           0 :         return path;
     203             :     }
     204             : 
     205           0 :     void draw(Target* target, const GrGeometryProcessor* gp) const {
     206           0 :         SkASSERT(!fAntiAlias);
     207           0 :         GrResourceProvider* rp = target->resourceProvider();
     208           0 :         bool inverseFill = fShape.inverseFilled();
     209             :         // construct a cache key from the path's genID and the view matrix
     210           0 :         static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
     211           0 :         GrUniqueKey key;
     212             :         static constexpr int kClipBoundsCnt = sizeof(fDevClipBounds) / sizeof(uint32_t);
     213           0 :         int shapeKeyDataCnt = fShape.unstyledKeySize();
     214           0 :         SkASSERT(shapeKeyDataCnt >= 0);
     215           0 :         GrUniqueKey::Builder builder(&key, kDomain, shapeKeyDataCnt + kClipBoundsCnt);
     216           0 :         fShape.writeUnstyledKey(&builder[0]);
     217             :         // For inverse fills, the tessellation is dependent on clip bounds.
     218           0 :         if (inverseFill) {
     219           0 :             memcpy(&builder[shapeKeyDataCnt], &fDevClipBounds, sizeof(fDevClipBounds));
     220             :         } else {
     221           0 :             memset(&builder[shapeKeyDataCnt], 0, sizeof(fDevClipBounds));
     222             :         }
     223           0 :         builder.finish();
     224           0 :         sk_sp<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrBuffer>(key));
     225             :         int actualCount;
     226           0 :         SkScalar tol = GrPathUtils::kDefaultTolerance;
     227           0 :         tol = GrPathUtils::scaleToleranceToSrc(tol, fViewMatrix, fShape.bounds());
     228           0 :         if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
     229           0 :             this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCount);
     230           0 :             return;
     231             :         }
     232             : 
     233           0 :         SkRect clipBounds = SkRect::Make(fDevClipBounds);
     234             : 
     235             :         SkMatrix vmi;
     236           0 :         if (!fViewMatrix.invert(&vmi)) {
     237           0 :             return;
     238             :         }
     239           0 :         vmi.mapRect(&clipBounds);
     240             :         bool isLinear;
     241           0 :         bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
     242           0 :         StaticVertexAllocator allocator(gp->getVertexStride(), rp, canMapVB);
     243           0 :         int count = GrTessellator::PathToTriangles(getPath(), tol, clipBounds, &allocator,
     244           0 :                                                    false, GrColor(), false, &isLinear);
     245           0 :         if (count == 0) {
     246           0 :             return;
     247             :         }
     248           0 :         this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count);
     249             :         TessInfo info;
     250           0 :         info.fTolerance = isLinear ? 0 : tol;
     251           0 :         info.fCount = count;
     252           0 :         key.setCustomData(SkData::MakeWithCopy(&info, sizeof(info)));
     253           0 :         rp->assignUniqueKeyToResource(key, allocator.vertexBuffer());
     254             :     }
     255             : 
     256           0 :     void drawAA(Target* target, const GrGeometryProcessor* gp) const {
     257           0 :         SkASSERT(fAntiAlias);
     258           0 :         SkPath path = getPath();
     259           0 :         if (path.isEmpty()) {
     260           0 :             return;
     261             :         }
     262           0 :         SkRect clipBounds = SkRect::Make(fDevClipBounds);
     263           0 :         path.transform(fViewMatrix);
     264           0 :         SkScalar tol = GrPathUtils::kDefaultTolerance;
     265             :         bool isLinear;
     266           0 :         DynamicVertexAllocator allocator(gp->getVertexStride(), target);
     267           0 :         int count = GrTessellator::PathToTriangles(path, tol, clipBounds, &allocator,
     268           0 :                                                    true, fColor, fCanTweakAlphaForCoverage,
     269           0 :                                                    &isLinear);
     270           0 :         if (count == 0) {
     271           0 :             return;
     272             :         }
     273           0 :         drawVertices(target, gp, allocator.vertexBuffer(), allocator.firstVertex(), count);
     274             :     }
     275             : 
     276           0 :     void onPrepareDraws(Target* target) const override {
     277           0 :         sk_sp<GrGeometryProcessor> gp;
     278             :         {
     279             :             using namespace GrDefaultGeoProcFactory;
     280             : 
     281           0 :             Color color(fColor);
     282           0 :             LocalCoords::Type localCoordsType = fNeedsLocalCoords
     283           0 :                                                         ? LocalCoords::kUsePosition_Type
     284           0 :                                                         : LocalCoords::kUnused_Type;
     285             :             Coverage::Type coverageType;
     286           0 :             if (fAntiAlias) {
     287           0 :                 color = Color(Color::kPremulGrColorAttribute_Type);
     288           0 :                 if (fCanTweakAlphaForCoverage) {
     289           0 :                     coverageType = Coverage::kSolid_Type;
     290             :                 } else {
     291           0 :                     coverageType = Coverage::kAttribute_Type;
     292             :                 }
     293             :             } else {
     294           0 :                 coverageType = Coverage::kSolid_Type;
     295             :             }
     296           0 :             if (fAntiAlias) {
     297           0 :                 gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(color, coverageType,
     298           0 :                                                                  localCoordsType, fViewMatrix);
     299             :             } else {
     300           0 :                 gp = GrDefaultGeoProcFactory::Make(color, coverageType, localCoordsType,
     301           0 :                                                    fViewMatrix);
     302             :             }
     303             :         }
     304           0 :         if (!gp.get()) {
     305           0 :             return;
     306             :         }
     307           0 :         if (fAntiAlias) {
     308           0 :             this->drawAA(target, gp.get());
     309             :         } else {
     310           0 :             this->draw(target, gp.get());
     311             :         }
     312             :     }
     313             : 
     314           0 :     void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrBuffer* vb,
     315             :                       int firstVertex, int count) const {
     316             :         GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimitiveType
     317           0 :                                                               : kTriangles_GrPrimitiveType;
     318           0 :         GrMesh mesh;
     319           0 :         mesh.init(primitiveType, vb, firstVertex, count);
     320           0 :         target->draw(gp, this->pipeline(), mesh);
     321           0 :     }
     322             : 
     323           0 :     bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
     324             : 
     325           0 :     TessellatingPathOp(const GrColor& color,
     326             :                        const GrShape& shape,
     327             :                        const SkMatrix& viewMatrix,
     328             :                        const SkIRect& devClipBounds,
     329             :                        bool antiAlias)
     330           0 :             : INHERITED(ClassID())
     331           0 :             , fColor(color)
     332             :             , fShape(shape)
     333             :             , fViewMatrix(viewMatrix)
     334             :             , fDevClipBounds(devClipBounds)
     335           0 :             , fAntiAlias(antiAlias) {
     336             :         SkRect devBounds;
     337           0 :         viewMatrix.mapRect(&devBounds, shape.bounds());
     338           0 :         if (shape.inverseFilled()) {
     339             :             // Because the clip bounds are used to add a contour for inverse fills, they must also
     340             :             // include the path bounds.
     341           0 :             devBounds.join(SkRect::Make(fDevClipBounds));
     342             :         }
     343           0 :         this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo);
     344           0 :     }
     345             : 
     346             :     GrColor                 fColor;
     347             :     GrShape                 fShape;
     348             :     SkMatrix                fViewMatrix;
     349             :     SkIRect                 fDevClipBounds;
     350             :     bool                    fAntiAlias;
     351             :     bool                    fCanTweakAlphaForCoverage;
     352             :     bool                    fNeedsLocalCoords;
     353             : 
     354             :     typedef GrLegacyMeshDrawOp INHERITED;
     355             : };
     356             : 
     357           0 : bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
     358           0 :     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
     359             :                               "GrTessellatingPathRenderer::onDrawPath");
     360             :     SkIRect clipBoundsI;
     361           0 :     args.fClip->getConservativeBounds(args.fRenderTargetContext->width(),
     362           0 :                                       args.fRenderTargetContext->height(),
     363           0 :                                       &clipBoundsI);
     364             :     std::unique_ptr<GrLegacyMeshDrawOp> op =
     365           0 :             TessellatingPathOp::Make(args.fPaint.getColor(),
     366           0 :                                      *args.fShape,
     367           0 :                                      *args.fViewMatrix,
     368             :                                      clipBoundsI,
     369           0 :                                      GrAAType::kCoverage == args.fAAType);
     370           0 :     GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType);
     371           0 :     pipelineBuilder.setUserStencil(args.fUserStencilSettings);
     372           0 :     args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip,
     373           0 :                                                    std::move(op));
     374           0 :     return true;
     375             : }
     376             : 
     377             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     378             : 
     379             : #if GR_TEST_UTILS
     380             : 
     381           0 : DRAW_OP_TEST_DEFINE(TesselatingPathOp) {
     382           0 :     GrColor color = GrRandomColor(random);
     383           0 :     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
     384           0 :     SkPath path = GrTest::TestPath(random);
     385             :     SkIRect devClipBounds = SkIRect::MakeLTRB(
     386           0 :         random->nextU(), random->nextU(), random->nextU(), random->nextU());
     387           0 :     devClipBounds.sort();
     388           0 :     bool antiAlias = random->nextBool();
     389           0 :     GrStyle style;
     390           0 :     do {
     391           0 :         GrTest::TestStyle(random, &style);
     392           0 :     } while (!style.isSimpleFill());
     393           0 :     GrShape shape(path, style);
     394           0 :     return TessellatingPathOp::Make(color, shape, viewMatrix, devClipBounds, antiAlias);
     395             : }
     396             : 
     397             : #endif

Generated by: LCOV version 1.13