Home | History | Annotate | Download | only in batches
      1 
      2 /*
      3  * Copyright 2015 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "GrAALinearizingConvexPathRenderer.h"
     10 
     11 #include "GrAAConvexTessellator.h"
     12 #include "GrBatchFlushState.h"
     13 #include "GrBatchTest.h"
     14 #include "GrContext.h"
     15 #include "GrDefaultGeoProcFactory.h"
     16 #include "GrGeometryProcessor.h"
     17 #include "GrInvariantOutput.h"
     18 #include "GrPathUtils.h"
     19 #include "GrProcessor.h"
     20 #include "GrPipelineBuilder.h"
     21 #include "GrStrokeInfo.h"
     22 #include "SkGeometry.h"
     23 #include "SkString.h"
     24 #include "SkTraceEvent.h"
     25 #include "SkPathPriv.h"
     26 #include "batches/GrVertexBatch.h"
     27 #include "glsl/GrGLSLGeometryProcessor.h"
     28 
     29 static const int DEFAULT_BUFFER_SIZE = 100;
     30 
     31 // The thicker the stroke, the harder it is to produce high-quality results using tessellation. For
     32 // the time being, we simply drop back to software rendering above this stroke width.
     33 static const SkScalar kMaxStrokeWidth = 20.0;
     34 
     35 GrAALinearizingConvexPathRenderer::GrAALinearizingConvexPathRenderer() {
     36 }
     37 
     38 ///////////////////////////////////////////////////////////////////////////////
     39 
     40 bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     41     if (!args.fAntiAlias) {
     42         return false;
     43     }
     44     if (args.fPath->isInverseFillType()) {
     45         return false;
     46     }
     47     if (!args.fPath->isConvex()) {
     48         return false;
     49     }
     50     if (args.fStroke->getStyle() == SkStrokeRec::kStroke_Style) {
     51         if (!args.fViewMatrix->isSimilarity()) {
     52             return false;
     53         }
     54         SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * args.fStroke->getWidth();
     55         return strokeWidth >= 1.0f && strokeWidth <= kMaxStrokeWidth && !args.fStroke->isDashed() &&
     56                 SkPathPriv::IsClosedSingleContour(*args.fPath) &&
     57                 args.fStroke->getJoin() != SkPaint::Join::kRound_Join;
     58     }
     59     return args.fStroke->getStyle() == SkStrokeRec::kFill_Style;
     60 }
     61 
     62 // extract the result vertices and indices from the GrAAConvexTessellator
     63 static void extract_verts(const GrAAConvexTessellator& tess,
     64                           void* vertices,
     65                           size_t vertexStride,
     66                           GrColor color,
     67                           uint16_t firstIndex,
     68                           uint16_t* idxs,
     69                           bool tweakAlphaForCoverage) {
     70     intptr_t verts = reinterpret_cast<intptr_t>(vertices);
     71 
     72     for (int i = 0; i < tess.numPts(); ++i) {
     73         *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i);
     74     }
     75 
     76     // Make 'verts' point to the colors
     77     verts += sizeof(SkPoint);
     78     for (int i = 0; i < tess.numPts(); ++i) {
     79         if (tweakAlphaForCoverage) {
     80             SkASSERT(SkScalarRoundToInt(255.0f * tess.coverage(i)) <= 255);
     81             unsigned scale = SkScalarRoundToInt(255.0f * tess.coverage(i));
     82             GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
     83             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
     84         } else {
     85             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
     86             *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
     87                     tess.coverage(i);
     88         }
     89     }
     90 
     91     for (int i = 0; i < tess.numIndices(); ++i) {
     92         idxs[i] = tess.index(i) + firstIndex;
     93     }
     94 }
     95 
     96 static const GrGeometryProcessor* create_fill_gp(bool tweakAlphaForCoverage,
     97                                                  const SkMatrix& viewMatrix,
     98                                                  bool usesLocalCoords,
     99                                                  bool coverageIgnored) {
    100     using namespace GrDefaultGeoProcFactory;
    101 
    102     Color color(Color::kAttribute_Type);
    103     Coverage::Type coverageType;
    104     // TODO remove coverage if coverage is ignored
    105     /*if (coverageIgnored) {
    106         coverageType = Coverage::kNone_Type;
    107     } else*/ if (tweakAlphaForCoverage) {
    108         coverageType = Coverage::kSolid_Type;
    109     } else {
    110         coverageType = Coverage::kAttribute_Type;
    111     }
    112     Coverage coverage(coverageType);
    113     LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type :
    114                                               LocalCoords::kUnused_Type);
    115     return CreateForDeviceSpace(color, coverage, localCoords, viewMatrix);
    116 }
    117 
    118 class AAFlatteningConvexPathBatch : public GrVertexBatch {
    119 public:
    120     DEFINE_BATCH_CLASS_ID
    121 
    122     struct Geometry {
    123         GrColor fColor;
    124         SkMatrix fViewMatrix;
    125         SkPath fPath;
    126         SkScalar fStrokeWidth;
    127         SkPaint::Join fJoin;
    128         SkScalar fMiterLimit;
    129     };
    130 
    131     static GrDrawBatch* Create(const Geometry& geometry) {
    132         return new AAFlatteningConvexPathBatch(geometry);
    133     }
    134 
    135     const char* name() const override { return "AAConvexBatch"; }
    136 
    137     void computePipelineOptimizations(GrInitInvariantOutput* color,
    138                                       GrInitInvariantOutput* coverage,
    139                                       GrBatchToXPOverrides* overrides) const override {
    140         // When this is called on a batch, there is only one geometry bundle
    141         color->setKnownFourComponents(fGeoData[0].fColor);
    142         coverage->setUnknownSingleComponent();
    143     }
    144 
    145 private:
    146     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
    147         // Handle any color overrides
    148         if (!overrides.readsColor()) {
    149             fGeoData[0].fColor = GrColor_ILLEGAL;
    150         }
    151         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
    152 
    153         // setup batch properties
    154         fBatch.fColorIgnored = !overrides.readsColor();
    155         fBatch.fColor = fGeoData[0].fColor;
    156         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
    157         fBatch.fCoverageIgnored = !overrides.readsCoverage();
    158         fBatch.fLinesOnly = SkPath::kLine_SegmentMask == fGeoData[0].fPath.getSegmentMasks();
    159         fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage();
    160     }
    161 
    162     void draw(GrVertexBatch::Target* target, const GrPipeline* pipeline, int vertexCount,
    163               size_t vertexStride, void* vertices, int indexCount, uint16_t* indices) const {
    164         if (vertexCount == 0 || indexCount == 0) {
    165             return;
    166         }
    167         const GrVertexBuffer* vertexBuffer;
    168         GrVertices info;
    169         int firstVertex;
    170         void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
    171                                               &firstVertex);
    172         if (!verts) {
    173             SkDebugf("Could not allocate vertices\n");
    174             return;
    175         }
    176         memcpy(verts, vertices, vertexCount * vertexStride);
    177 
    178         const GrIndexBuffer* indexBuffer;
    179         int firstIndex;
    180         uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
    181         if (!idxs) {
    182             SkDebugf("Could not allocate indices\n");
    183             return;
    184         }
    185         memcpy(idxs, indices, indexCount * sizeof(uint16_t));
    186         info.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex,
    187                 firstIndex, vertexCount, indexCount);
    188         target->draw(info);
    189     }
    190 
    191     void onPrepareDraws(Target* target) const override {
    192         bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
    193 
    194         // Setup GrGeometryProcessor
    195         SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_gp(canTweakAlphaForCoverage,
    196                                                                   this->viewMatrix(),
    197                                                                   this->usesLocalCoords(),
    198                                                                   this->coverageIgnored()));
    199         if (!gp) {
    200             SkDebugf("Couldn't create a GrGeometryProcessor\n");
    201             return;
    202         }
    203 
    204         target->initDraw(gp, this->pipeline());
    205 
    206         size_t vertexStride = gp->getVertexStride();
    207 
    208         SkASSERT(canTweakAlphaForCoverage ?
    209                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
    210                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
    211 
    212         int instanceCount = fGeoData.count();
    213 
    214         int vertexCount = 0;
    215         int indexCount = 0;
    216         int maxVertices = DEFAULT_BUFFER_SIZE;
    217         int maxIndices = DEFAULT_BUFFER_SIZE;
    218         uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride);
    219         uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t));
    220         for (int i = 0; i < instanceCount; i++) {
    221             const Geometry& args = fGeoData[i];
    222             GrAAConvexTessellator tess(args.fStrokeWidth, args.fJoin, args.fMiterLimit);
    223 
    224             if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
    225                 continue;
    226             }
    227 
    228             int currentIndices = tess.numIndices();
    229             SkASSERT(currentIndices <= UINT16_MAX);
    230             if (indexCount + currentIndices > UINT16_MAX) {
    231                 // if we added the current instance, we would overflow the indices we can store in a
    232                 // uint16_t. Draw what we've got so far and reset.
    233                 this->draw(target, this->pipeline(), vertexCount, vertexStride, vertices,
    234                            indexCount, indices);
    235                 vertexCount = 0;
    236                 indexCount = 0;
    237             }
    238             int currentVertices = tess.numPts();
    239             if (vertexCount + currentVertices > maxVertices) {
    240                 maxVertices = SkTMax(vertexCount + currentVertices, maxVertices * 2);
    241                 vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride);
    242             }
    243             if (indexCount + currentIndices > maxIndices) {
    244                 maxIndices = SkTMax(indexCount + currentIndices, maxIndices * 2);
    245                 indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
    246             }
    247 
    248             extract_verts(tess, vertices + vertexStride * vertexCount, vertexStride, args.fColor,
    249                     vertexCount, indices + indexCount, canTweakAlphaForCoverage);
    250             vertexCount += currentVertices;
    251             indexCount += currentIndices;
    252         }
    253         this->draw(target, this->pipeline(), vertexCount, vertexStride, vertices, indexCount,
    254                    indices);
    255         sk_free(vertices);
    256         sk_free(indices);
    257     }
    258 
    259     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
    260 
    261     AAFlatteningConvexPathBatch(const Geometry& geometry) : INHERITED(ClassID()) {
    262         fGeoData.push_back(geometry);
    263 
    264         // compute bounds
    265         fBounds = geometry.fPath.getBounds();
    266         SkScalar w = geometry.fStrokeWidth;
    267         if (w > 0) {
    268             w /= 2;
    269             // If the miter limit is < 1 then we effectively fallback to bevel joins.
    270             if (SkPaint::kMiter_Join == geometry.fJoin && w > 1.f) {
    271                 w *= geometry.fMiterLimit;
    272             }
    273             fBounds.outset(w, w);
    274         }
    275         geometry.fViewMatrix.mapRect(&fBounds);
    276     }
    277 
    278     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
    279         AAFlatteningConvexPathBatch* that = t->cast<AAFlatteningConvexPathBatch>();
    280         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
    281                                     that->bounds(), caps)) {
    282             return false;
    283         }
    284 
    285         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
    286         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
    287             return false;
    288         }
    289 
    290         // In the event of two batches, one who can tweak, one who cannot, we just fall back to
    291         // not tweaking
    292         if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
    293             fBatch.fCanTweakAlphaForCoverage = false;
    294         }
    295 
    296         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
    297         this->joinBounds(that->bounds());
    298         return true;
    299     }
    300 
    301     GrColor color() const { return fBatch.fColor; }
    302     bool linesOnly() const { return fBatch.fLinesOnly; }
    303     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
    304     bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
    305     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
    306     bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
    307 
    308     struct BatchTracker {
    309         GrColor fColor;
    310         bool fUsesLocalCoords;
    311         bool fColorIgnored;
    312         bool fCoverageIgnored;
    313         bool fLinesOnly;
    314         bool fCanTweakAlphaForCoverage;
    315     };
    316 
    317     BatchTracker fBatch;
    318     SkSTArray<1, Geometry, true> fGeoData;
    319 
    320     typedef GrVertexBatch INHERITED;
    321 };
    322 
    323 bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
    324     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
    325                               "GrAALinearizingConvexPathRenderer::onDrawPath");
    326     if (args.fPath->isEmpty()) {
    327         return true;
    328     }
    329     AAFlatteningConvexPathBatch::Geometry geometry;
    330     geometry.fColor = args.fColor;
    331     geometry.fViewMatrix = *args.fViewMatrix;
    332     geometry.fPath = *args.fPath;
    333     geometry.fStrokeWidth = args.fStroke->isFillStyle() ? -1.0f : args.fStroke->getWidth();
    334     geometry.fJoin = args.fStroke->isFillStyle() ? SkPaint::Join::kMiter_Join :
    335                                                    args.fStroke->getJoin();
    336     geometry.fMiterLimit = args.fStroke->getMiter();
    337 
    338     SkAutoTUnref<GrDrawBatch> batch(AAFlatteningConvexPathBatch::Create(geometry));
    339     args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
    340 
    341     return true;
    342 }
    343 
    344 ///////////////////////////////////////////////////////////////////////////////////////////////////
    345 
    346 #ifdef GR_TEST_UTILS
    347 
    348 DRAW_BATCH_TEST_DEFINE(AAFlatteningConvexPathBatch) {
    349     AAFlatteningConvexPathBatch::Geometry geometry;
    350     geometry.fColor = GrRandomColor(random);
    351     geometry.fViewMatrix = GrTest::TestMatrixInvertible(random);
    352     geometry.fPath = GrTest::TestPathConvex(random);
    353 
    354     return AAFlatteningConvexPathBatch::Create(geometry);
    355 }
    356 
    357 #endif
    358