GrAALinearizingConvexPathRenderer.cpp revision 5ed4423090e63e4c7888d6dd44fde177adea13f3
11a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas/*
21a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas * Copyright 2015 Google Inc.
31a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas *
41a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas * Use of this source code is governed by a BSD-style license that can be
51a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas * found in the LICENSE file.
61a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas */
71a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
81a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "GrAALinearizingConvexPathRenderer.h"
91a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "GrAAConvexTessellator.h"
101a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "GrContext.h"
111a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "GrDefaultGeoProcFactory.h"
125ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian Salomon#include "GrDrawOpTest.h"
131a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "GrGeometryProcessor.h"
14742e31de1599f3902810aecdf2e2e3eed3b40a09Brian Salomon#include "GrOpFlushState.h"
151a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "GrPathUtils.h"
16dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon#include "GrProcessor.h"
176663acff010ce752e4bf778da81fa97448c9db31bsalomon#include "GrStyle.h"
181a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "SkGeometry.h"
19dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon#include "SkPathPriv.h"
201a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "SkString.h"
211a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "SkTraceEvent.h"
22e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel#include "glsl/GrGLSLGeometryProcessor.h"
23895274391db8df7357334aec260edca2e1735626Brian Salomon#include "ops/GrMeshDrawOp.h"
24b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon#include "ops/GrSimpleMeshDrawOpHelper.h"
251a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
26bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalitastatic const int DEFAULT_BUFFER_SIZE = 100;
27bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita
28bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita// The thicker the stroke, the harder it is to produce high-quality results using tessellation. For
29bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita// the time being, we simply drop back to software rendering above this stroke width.
30bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalitastatic const SkScalar kMaxStrokeWidth = 20.0;
311a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
321a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholasGrAALinearizingConvexPathRenderer::GrAALinearizingConvexPathRenderer() {
331a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas}
341a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
351a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas///////////////////////////////////////////////////////////////////////////////
361a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
375ed4423090e63e4c7888d6dd44fde177adea13f3Chris DaltonGrPathRenderer::CanDrawPath
385ed4423090e63e4c7888d6dd44fde177adea13f3Chris DaltonGrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
390e8fc8b9e6a138cf4a66b421fb824679df717329Brian Salomon    if (GrAAType::kCoverage != args.fAAType) {
405ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton        return CanDrawPath::kNo;
41bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita    }
428acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    if (!args.fShape->knownToBeConvex()) {
435ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton        return CanDrawPath::kNo;
44bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita    }
458acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    if (args.fShape->style().pathEffect()) {
465ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton        return CanDrawPath::kNo;
47bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita    }
488acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    if (args.fShape->inverseFilled()) {
495ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton        return CanDrawPath::kNo;
506663acff010ce752e4bf778da81fa97448c9db31bsalomon    }
51a98e399ba5aa6261f60e18c627777eec35b7b147Brian Osman    if (args.fShape->bounds().width() <= 0 && args.fShape->bounds().height() <= 0) {
52a98e399ba5aa6261f60e18c627777eec35b7b147Brian Osman        // Stroked zero length lines should draw, but this PR doesn't handle that case
535ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton        return CanDrawPath::kNo;
54a98e399ba5aa6261f60e18c627777eec35b7b147Brian Osman    }
558acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    const SkStrokeRec& stroke = args.fShape->style().strokeRec();
568c170971f182d47bc9af71fc88a607740d03dfd5robertphillips
578c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
588c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
59fea7763140ba74b78f2c30028452e250140b6f21ethannicholas        if (!args.fViewMatrix->isSimilarity()) {
605ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton            return CanDrawPath::kNo;
61fea7763140ba74b78f2c30028452e250140b6f21ethannicholas        }
626663acff010ce752e4bf778da81fa97448c9db31bsalomon        SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
638c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) {
645ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton            return CanDrawPath::kNo;
658c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        }
665ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton        if (strokeWidth > kMaxStrokeWidth ||
675ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton            !args.fShape->knownToBeClosed() ||
685ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton            stroke.getJoin() == SkPaint::Join::kRound_Join) {
695ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton            return CanDrawPath::kNo;
705ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton        }
715ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton        return CanDrawPath::kYes;
725ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton    }
735ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton    if (stroke.getStyle() != SkStrokeRec::kFill_Style) {
745ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton        return CanDrawPath::kNo;
75bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita    }
765ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton    return CanDrawPath::kYes;
771a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas}
781a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
791a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas// extract the result vertices and indices from the GrAAConvexTessellator
801a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholasstatic void extract_verts(const GrAAConvexTessellator& tess,
811a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                          void* vertices,
821a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                          size_t vertexStride,
831a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                          GrColor color,
841a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                          uint16_t firstIndex,
851a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                          uint16_t* idxs,
861a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                          bool tweakAlphaForCoverage) {
871a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    intptr_t verts = reinterpret_cast<intptr_t>(vertices);
881a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
891a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    for (int i = 0; i < tess.numPts(); ++i) {
901a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i);
911a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
921a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
931a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    // Make 'verts' point to the colors
941a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    verts += sizeof(SkPoint);
951a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    for (int i = 0; i < tess.numPts(); ++i) {
961a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        if (tweakAlphaForCoverage) {
97bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita            SkASSERT(SkScalarRoundToInt(255.0f * tess.coverage(i)) <= 255);
98bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita            unsigned scale = SkScalarRoundToInt(255.0f * tess.coverage(i));
991a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
1001a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
1011a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        } else {
1021a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
103002c2ce66be69d41632c9603ce62c50f04156518mtklein            *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
104bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita                    tess.coverage(i);
1051a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
1061a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
1071a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
1081a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    for (int i = 0; i < tess.numIndices(); ++i) {
1091a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        idxs[i] = tess.index(i) + firstIndex;
1101a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
1111a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas}
1121a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
11360fb0b2548c7f03b58fc52aa298b07ed137c84e3Brian Salomonstatic sk_sp<GrGeometryProcessor> create_lines_only_gp(bool tweakAlphaForCoverage,
11460fb0b2548c7f03b58fc52aa298b07ed137c84e3Brian Salomon                                                       const SkMatrix& viewMatrix,
11560fb0b2548c7f03b58fc52aa298b07ed137c84e3Brian Salomon                                                       bool usesLocalCoords) {
116df0c55785033c191d2d509c22662861588e4acd8joshualitt    using namespace GrDefaultGeoProcFactory;
117df0c55785033c191d2d509c22662861588e4acd8joshualitt
118df0c55785033c191d2d509c22662861588e4acd8joshualitt    Coverage::Type coverageType;
1198c852be264d003b2e610c5b8634bc0f81c46bbbaBrian Salomon    if (tweakAlphaForCoverage) {
120df0c55785033c191d2d509c22662861588e4acd8joshualitt        coverageType = Coverage::kSolid_Type;
121df0c55785033c191d2d509c22662861588e4acd8joshualitt    } else {
122df0c55785033c191d2d509c22662861588e4acd8joshualitt        coverageType = Coverage::kAttribute_Type;
1231a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
1248c852be264d003b2e610c5b8634bc0f81c46bbbaBrian Salomon    LocalCoords::Type localCoordsType =
1258c852be264d003b2e610c5b8634bc0f81c46bbbaBrian Salomon            usesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type;
1263de0aee181b8fe0013b15100cba7381eb0468db4Brian Salomon    return MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type, coverageType, localCoordsType,
1273de0aee181b8fe0013b15100cba7381eb0468db4Brian Salomon                              viewMatrix);
1281a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas}
1291a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
130b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomonnamespace {
1311a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
132b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomonclass AAFlatteningConvexPathOp final : public GrMeshDrawOp {
133b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomonprivate:
134b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    using Helper = GrSimpleMeshDrawOpHelperWithStencil;
1357c3e7180948766321c51d165737555e78910de51Brian Salomon
136b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomonpublic:
137b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    DEFINE_OP_CLASS_ID
138b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint,
139b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                          const SkMatrix& viewMatrix,
140b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                          const SkPath& path,
141b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                          SkScalar strokeWidth,
142b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                          SkStrokeRec::Style style,
143b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                          SkPaint::Join join,
144b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                          SkScalar miterLimit,
145b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                          const GrUserStencilSettings* stencilSettings) {
146b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        return Helper::FactoryHelper<AAFlatteningConvexPathOp>(std::move(paint), viewMatrix, path,
147b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                                               strokeWidth, style, join, miterLimit,
148b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                                               stencilSettings);
1497c3e7180948766321c51d165737555e78910de51Brian Salomon    }
1501a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
151b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    AAFlatteningConvexPathOp(const Helper::MakeArgs& helperArgs,
152b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                             GrColor color,
153780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon                             const SkMatrix& viewMatrix,
154780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon                             const SkPath& path,
155780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon                             SkScalar strokeWidth,
156780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon                             SkStrokeRec::Style style,
157780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon                             SkPaint::Join join,
158b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                             SkScalar miterLimit,
159b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                             const GrUserStencilSettings* stencilSettings)
160b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon            : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencilSettings) {
161780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        fPaths.emplace_back(
162780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon                PathData{color, viewMatrix, path, strokeWidth, style, join, miterLimit});
163780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon
164780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        // compute bounds
165780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        SkRect bounds = path.getBounds();
166780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        SkScalar w = strokeWidth;
167780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        if (w > 0) {
168780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon            w /= 2;
169780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon            // If the half stroke width is < 1 then we effectively fallback to bevel joins.
170780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon            if (SkPaint::kMiter_Join == join && w > 1.f) {
171780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon                w *= miterLimit;
172780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon            }
173780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon            bounds.outset(w, w);
174780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        }
175780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kYes, IsZeroArea::kNo);
176780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon    }
177780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon
178b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    const char* name() const override { return "AAFlatteningConvexPathOp"; }
179b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon
180b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    SkString dumpInfo() const override {
181b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        SkString string;
182b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        for (const auto& path : fPaths) {
183b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon            string.appendf(
184b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                    "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, "
185b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                    "MiterLimit: %.2f\n",
186b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                    path.fColor, path.fStrokeWidth, path.fStyle, path.fJoin, path.fMiterLimit);
187b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        }
188b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        string += fHelper.dumpInfo();
189b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        string += INHERITED::dumpInfo();
190b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        return string;
19192aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    }
19292aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon
193b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
194b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon
195b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
196b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kSingleChannel,
197b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                            &fPaths.back().fColor);
1981a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
1991a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
200b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomonprivate:
201b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    void draw(GrMeshDrawOp::Target* target, const GrGeometryProcessor* gp,
202b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon              const GrPipeline* pipeline, int vertexCount, size_t vertexStride, void* vertices,
203b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon              int indexCount, uint16_t* indices) const {
2041a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        if (vertexCount == 0 || indexCount == 0) {
2051a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            return;
2061a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
207ff926502069d0ddafaecc18dc08973762e4befd2Chris Dalton        const GrBuffer* vertexBuffer;
2083809bab7ed344ad140346c38e149dabf10bd525fChris Dalton        GrMesh mesh(GrPrimitiveType::kTriangles);
209bca46e29e9f96999df0b38fb9359e71b73217c94Chris Dalton        int firstVertex;
210002c2ce66be69d41632c9603ce62c50f04156518mtklein        void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
211bca46e29e9f96999df0b38fb9359e71b73217c94Chris Dalton                                              &firstVertex);
2121a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        if (!verts) {
2131a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            SkDebugf("Could not allocate vertices\n");
2141a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            return;
2151a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
2161a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        memcpy(verts, vertices, vertexCount * vertexStride);
2171a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
218397536cabe12a9936659870dd220c869789424bacdalton        const GrBuffer* indexBuffer;
219bca46e29e9f96999df0b38fb9359e71b73217c94Chris Dalton        int firstIndex;
220bca46e29e9f96999df0b38fb9359e71b73217c94Chris Dalton        uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
2211a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        if (!idxs) {
2221a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            SkDebugf("Could not allocate indices\n");
2231a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            return;
2241a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
2251a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        memcpy(idxs, indices, indexCount * sizeof(uint16_t));
226114a3c0b2b26c84b9d0907a99fd8ab7938631246Chris Dalton        mesh.setIndexed(indexBuffer, indexCount, firstIndex, 0, vertexCount - 1);
227114a3c0b2b26c84b9d0907a99fd8ab7938631246Chris Dalton        mesh.setVertexData(vertexBuffer, firstVertex);
228b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        target->draw(gp, pipeline, mesh);
2291a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
230002c2ce66be69d41632c9603ce62c50f04156518mtklein
23191326c34ee1f1531d62caa153746821b58e6e55dBrian Salomon    void onPrepareDraws(Target* target) override {
232b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        const GrPipeline* pipeline = fHelper.makePipeline(target);
2331a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
234df0c55785033c191d2d509c22662861588e4acd8joshualitt        // Setup GrGeometryProcessor
235b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        sk_sp<GrGeometryProcessor> gp(create_lines_only_gp(fHelper.compatibleWithAlphaAsCoverage(),
236b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                                           this->viewMatrix(),
237b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                                           fHelper.usesLocalCoords()));
238df0c55785033c191d2d509c22662861588e4acd8joshualitt        if (!gp) {
239df0c55785033c191d2d509c22662861588e4acd8joshualitt            SkDebugf("Couldn't create a GrGeometryProcessor\n");
2401a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            return;
2411a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
2421a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
2431a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        size_t vertexStride = gp->getVertexStride();
2441a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
245b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        SkASSERT(fHelper.compatibleWithAlphaAsCoverage()
246b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                         ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)
247b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                         : vertexStride ==
248b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                   sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
2491a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
250780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        int instanceCount = fPaths.count();
2511a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
2521a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        int vertexCount = 0;
2531a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        int indexCount = 0;
2541a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        int maxVertices = DEFAULT_BUFFER_SIZE;
2551a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        int maxIndices = DEFAULT_BUFFER_SIZE;
256002c2ce66be69d41632c9603ce62c50f04156518mtklein        uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride);
257002c2ce66be69d41632c9603ce62c50f04156518mtklein        uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t));
2581a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        for (int i = 0; i < instanceCount; i++) {
259780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon            const PathData& args = fPaths[i];
2608c170971f182d47bc9af71fc88a607740d03dfd5robertphillips            GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth,
2618c170971f182d47bc9af71fc88a607740d03dfd5robertphillips                                       args.fJoin, args.fMiterLimit);
2621a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
2631a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
2641a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                continue;
2651a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            }
2661a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
2671a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            int currentIndices = tess.numIndices();
2681a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            SkASSERT(currentIndices <= UINT16_MAX);
2691a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            if (indexCount + currentIndices > UINT16_MAX) {
270002c2ce66be69d41632c9603ce62c50f04156518mtklein                // if we added the current instance, we would overflow the indices we can store in a
2711a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                // uint16_t. Draw what we've got so far and reset.
272b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                this->draw(target, gp.get(), pipeline, vertexCount, vertexStride, vertices,
273b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                           indexCount, indices);
2741a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                vertexCount = 0;
2751a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                indexCount = 0;
2761a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            }
2771a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            int currentVertices = tess.numPts();
2781a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            if (vertexCount + currentVertices > maxVertices) {
2791a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                maxVertices = SkTMax(vertexCount + currentVertices, maxVertices * 2);
280002c2ce66be69d41632c9603ce62c50f04156518mtklein                vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride);
2811a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            }
2821a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            if (indexCount + currentIndices > maxIndices) {
2831a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                maxIndices = SkTMax(indexCount + currentIndices, maxIndices * 2);
284002c2ce66be69d41632c9603ce62c50f04156518mtklein                indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
2851a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            }
2861a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
287002c2ce66be69d41632c9603ce62c50f04156518mtklein            extract_verts(tess, vertices + vertexStride * vertexCount, vertexStride, args.fColor,
288b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                          vertexCount, indices + indexCount,
289b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                          fHelper.compatibleWithAlphaAsCoverage());
2901a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            vertexCount += currentVertices;
2911a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            indexCount += currentIndices;
2921a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
293b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        this->draw(target, gp.get(), pipeline, vertexCount, vertexStride, vertices, indexCount,
294b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                   indices);
295002c2ce66be69d41632c9603ce62c50f04156518mtklein        sk_free(vertices);
296002c2ce66be69d41632c9603ce62c50f04156518mtklein        sk_free(indices);
2971a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
2981a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
29925a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
300780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
301b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
3028cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
3038cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
3048cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
305780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
30688cf17d099085b8085ab11571b5094163dbb2c84bsalomon        this->joinBounds(*that);
3071a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        return true;
3081a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
3091a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
310780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon    const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }
3111a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
312780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon    struct PathData {
3130432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        GrColor fColor;
3140432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkMatrix fViewMatrix;
3150432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkPath fPath;
3160432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkScalar fStrokeWidth;
3178c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        SkStrokeRec::Style fStyle;
3180432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkPaint::Join fJoin;
3190432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkScalar fMiterLimit;
3200432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    };
3210432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon
322780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon    SkSTArray<1, PathData, true> fPaths;
323b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    Helper fHelper;
3241b55a963a2374a14bb82eb887bb99ee91680f0ebreed
325b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    typedef GrMeshDrawOp INHERITED;
3261a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas};
3271a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
328b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon}  // anonymous namespace
329b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon
3300aff2fa82a5fa9f99aa77327dac3e9e803b4ed07bsalomonbool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
3311105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman    GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
332de83b41cc7fc5bd1398e06c011e698215261665fjoshualitt                              "GrAALinearizingConvexPathRenderer::onDrawPath");
3337c8460e10135c05a42d0744b84838bbc24398ac2Brian Salomon    SkASSERT(GrFSAAType::kUnifiedMSAA != args.fRenderTargetContext->fsaaType());
3348acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    SkASSERT(!args.fShape->isEmpty());
3358c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    SkASSERT(!args.fShape->style().pathEffect());
336ecbc12b1c1c72de0cf7bba4a3f6a7cce4f43bf41csmartdalton
3370432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkPath path;
3380432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    args.fShape->asPath(&path);
3398acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    bool fill = args.fShape->style().isSimpleFill();
3408acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    const SkStrokeRec& stroke = args.fShape->style().strokeRec();
3410432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth();
3420432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin();
3430432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkScalar miterLimit = stroke.getMiter();
3441a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
345b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    std::unique_ptr<GrDrawOp> op = AAFlatteningConvexPathOp::Make(
346b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon            std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth, stroke.getStyle(), join,
347b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon            miterLimit, args.fUserStencilSettings);
348b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
3491a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    return true;
3501a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas}
3511a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
3521a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas///////////////////////////////////////////////////////////////////////////////////////////////////
3531a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
3546f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#if GR_TEST_UTILS
3551a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
356b295573c93e7a9a78ee736a399c256d7669b79beBrian SalomonGR_DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) {
357780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon    SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
3580432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkPath path = GrTest::TestPathConvex(random);
3598c170971f182d47bc9af71fc88a607740d03dfd5robertphillips
3608c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    SkStrokeRec::Style styles[3] = { SkStrokeRec::kFill_Style,
36160c05f98aa22d89e4ef25acb4799936f5df3cff2Herb Derby                                     SkStrokeRec::kStroke_Style,
3628c170971f182d47bc9af71fc88a607740d03dfd5robertphillips                                     SkStrokeRec::kStrokeAndFill_Style };
3638c170971f182d47bc9af71fc88a607740d03dfd5robertphillips
3648c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    SkStrokeRec::Style style = styles[random->nextU() % 3];
3658c170971f182d47bc9af71fc88a607740d03dfd5robertphillips
3668c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    SkScalar strokeWidth = -1.f;
3670432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkPaint::Join join = SkPaint::kMiter_Join;
3680432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkScalar miterLimit = 0.5f;
3698c170971f182d47bc9af71fc88a607740d03dfd5robertphillips
3708c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    if (SkStrokeRec::kFill_Style != style) {
3718c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        strokeWidth = random->nextRangeF(1.0f, 10.0f);
3728c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        if (random->nextBool()) {
3738c170971f182d47bc9af71fc88a607740d03dfd5robertphillips            join = SkPaint::kMiter_Join;
3748c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        } else {
3758c170971f182d47bc9af71fc88a607740d03dfd5robertphillips            join = SkPaint::kBevel_Join;
3768c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        }
3778c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        miterLimit = random->nextRangeF(0.5f, 2.0f);
3788c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    }
379b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context);
380b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    return AAFlatteningConvexPathOp::Make(std::move(paint), viewMatrix, path, strokeWidth, style,
381b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                          join, miterLimit, stencilSettings);
3821a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas}
3831a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
3841a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#endif
385