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
180f1748f5a9238a0d3e189d50fc5e57ae8b8ec087cRobert Phillips    void visitProxies(const VisitProxyFunc& func) const override {
181b493eebca14aefbd5f22fb5d45ba978b19db4b18Robert Phillips        fHelper.visitProxies(func);
182b493eebca14aefbd5f22fb5d45ba978b19db4b18Robert Phillips    }
183b493eebca14aefbd5f22fb5d45ba978b19db4b18Robert Phillips
184b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    SkString dumpInfo() const override {
185b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        SkString string;
186b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        for (const auto& path : fPaths) {
187b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon            string.appendf(
188b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                    "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, "
189b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                    "MiterLimit: %.2f\n",
190b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                    path.fColor, path.fStrokeWidth, path.fStyle, path.fJoin, path.fMiterLimit);
191b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        }
192b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        string += fHelper.dumpInfo();
193b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        string += INHERITED::dumpInfo();
194b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        return string;
19592aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    }
19692aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon
197b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
198b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon
1999a725dd9485654155e2e4196c32d372360bcdb61Brian Osman    RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip,
2009a725dd9485654155e2e4196c32d372360bcdb61Brian Osman                                GrPixelConfigIsClamped dstIsClamped) override {
2019a725dd9485654155e2e4196c32d372360bcdb61Brian Osman        return fHelper.xpRequiresDstTexture(caps, clip, dstIsClamped,
2029a725dd9485654155e2e4196c32d372360bcdb61Brian Osman                                            GrProcessorAnalysisCoverage::kSingleChannel,
203b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                            &fPaths.back().fColor);
2041a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
2051a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
206b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomonprivate:
207b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    void draw(GrMeshDrawOp::Target* target, const GrGeometryProcessor* gp,
208b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon              const GrPipeline* pipeline, int vertexCount, size_t vertexStride, void* vertices,
209b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon              int indexCount, uint16_t* indices) const {
2101a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        if (vertexCount == 0 || indexCount == 0) {
2111a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            return;
2121a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
213ff926502069d0ddafaecc18dc08973762e4befd2Chris Dalton        const GrBuffer* vertexBuffer;
2143809bab7ed344ad140346c38e149dabf10bd525fChris Dalton        GrMesh mesh(GrPrimitiveType::kTriangles);
215bca46e29e9f96999df0b38fb9359e71b73217c94Chris Dalton        int firstVertex;
216002c2ce66be69d41632c9603ce62c50f04156518mtklein        void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
217bca46e29e9f96999df0b38fb9359e71b73217c94Chris Dalton                                              &firstVertex);
2181a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        if (!verts) {
2191a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            SkDebugf("Could not allocate vertices\n");
2201a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            return;
2211a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
2221a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        memcpy(verts, vertices, vertexCount * vertexStride);
2231a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
224397536cabe12a9936659870dd220c869789424bacdalton        const GrBuffer* indexBuffer;
225bca46e29e9f96999df0b38fb9359e71b73217c94Chris Dalton        int firstIndex;
226bca46e29e9f96999df0b38fb9359e71b73217c94Chris Dalton        uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
2271a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        if (!idxs) {
2281a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            SkDebugf("Could not allocate indices\n");
2291a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            return;
2301a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
2311a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        memcpy(idxs, indices, indexCount * sizeof(uint16_t));
232114a3c0b2b26c84b9d0907a99fd8ab7938631246Chris Dalton        mesh.setIndexed(indexBuffer, indexCount, firstIndex, 0, vertexCount - 1);
233114a3c0b2b26c84b9d0907a99fd8ab7938631246Chris Dalton        mesh.setVertexData(vertexBuffer, firstVertex);
234b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        target->draw(gp, pipeline, mesh);
2351a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
236002c2ce66be69d41632c9603ce62c50f04156518mtklein
23791326c34ee1f1531d62caa153746821b58e6e55dBrian Salomon    void onPrepareDraws(Target* target) override {
238b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        const GrPipeline* pipeline = fHelper.makePipeline(target);
2391a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
240df0c55785033c191d2d509c22662861588e4acd8joshualitt        // Setup GrGeometryProcessor
241b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        sk_sp<GrGeometryProcessor> gp(create_lines_only_gp(fHelper.compatibleWithAlphaAsCoverage(),
242b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                                           this->viewMatrix(),
243b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                                           fHelper.usesLocalCoords()));
244df0c55785033c191d2d509c22662861588e4acd8joshualitt        if (!gp) {
245df0c55785033c191d2d509c22662861588e4acd8joshualitt            SkDebugf("Couldn't create a GrGeometryProcessor\n");
2461a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            return;
2471a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
2481a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
2491a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        size_t vertexStride = gp->getVertexStride();
2501a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
251b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        SkASSERT(fHelper.compatibleWithAlphaAsCoverage()
252b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                         ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)
253b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                         : vertexStride ==
254b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                   sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
2551a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
256780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        int instanceCount = fPaths.count();
2571a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
2581a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        int vertexCount = 0;
2591a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        int indexCount = 0;
2601a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        int maxVertices = DEFAULT_BUFFER_SIZE;
2611a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        int maxIndices = DEFAULT_BUFFER_SIZE;
262002c2ce66be69d41632c9603ce62c50f04156518mtklein        uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride);
263002c2ce66be69d41632c9603ce62c50f04156518mtklein        uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t));
2641a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        for (int i = 0; i < instanceCount; i++) {
265780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon            const PathData& args = fPaths[i];
2668c170971f182d47bc9af71fc88a607740d03dfd5robertphillips            GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth,
2678c170971f182d47bc9af71fc88a607740d03dfd5robertphillips                                       args.fJoin, args.fMiterLimit);
2681a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
2691a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
2701a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                continue;
2711a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            }
2721a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
2731a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            int currentIndices = tess.numIndices();
2741a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            if (indexCount + currentIndices > UINT16_MAX) {
275002c2ce66be69d41632c9603ce62c50f04156518mtklein                // if we added the current instance, we would overflow the indices we can store in a
2761a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                // uint16_t. Draw what we've got so far and reset.
277b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                this->draw(target, gp.get(), pipeline, vertexCount, vertexStride, vertices,
278b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                           indexCount, indices);
2791a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                vertexCount = 0;
2801a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                indexCount = 0;
2811a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            }
2821a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            int currentVertices = tess.numPts();
2831a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            if (vertexCount + currentVertices > maxVertices) {
2841a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                maxVertices = SkTMax(vertexCount + currentVertices, maxVertices * 2);
285002c2ce66be69d41632c9603ce62c50f04156518mtklein                vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride);
2861a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            }
2871a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            if (indexCount + currentIndices > maxIndices) {
2881a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas                maxIndices = SkTMax(indexCount + currentIndices, maxIndices * 2);
289002c2ce66be69d41632c9603ce62c50f04156518mtklein                indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
2901a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            }
2911a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
292002c2ce66be69d41632c9603ce62c50f04156518mtklein            extract_verts(tess, vertices + vertexStride * vertexCount, vertexStride, args.fColor,
293b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                          vertexCount, indices + indexCount,
294b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                          fHelper.compatibleWithAlphaAsCoverage());
2951a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            vertexCount += currentVertices;
2961a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas            indexCount += currentIndices;
2971a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        }
298b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        this->draw(target, gp.get(), pipeline, vertexCount, vertexStride, vertices, indexCount,
299b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                   indices);
300002c2ce66be69d41632c9603ce62c50f04156518mtklein        sk_free(vertices);
301002c2ce66be69d41632c9603ce62c50f04156518mtklein        sk_free(indices);
3021a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
3031a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
30425a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
305780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
306b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon        if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
3078cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
3088cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
3098cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
310780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon        fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
31188cf17d099085b8085ab11571b5094163dbb2c84bsalomon        this->joinBounds(*that);
3121a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas        return true;
3131a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    }
3141a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
315780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon    const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }
3161a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
317780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon    struct PathData {
3180432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        GrColor fColor;
3190432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkMatrix fViewMatrix;
3200432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkPath fPath;
3210432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkScalar fStrokeWidth;
3228c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        SkStrokeRec::Style fStyle;
3230432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkPaint::Join fJoin;
3240432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon        SkScalar fMiterLimit;
3250432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    };
3260432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon
327780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon    SkSTArray<1, PathData, true> fPaths;
328b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    Helper fHelper;
3291b55a963a2374a14bb82eb887bb99ee91680f0ebreed
330b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    typedef GrMeshDrawOp INHERITED;
3311a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas};
3321a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
333b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon}  // anonymous namespace
334b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon
3350aff2fa82a5fa9f99aa77327dac3e9e803b4ed07bsalomonbool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
3361105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman    GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
337de83b41cc7fc5bd1398e06c011e698215261665fjoshualitt                              "GrAALinearizingConvexPathRenderer::onDrawPath");
3387c8460e10135c05a42d0744b84838bbc24398ac2Brian Salomon    SkASSERT(GrFSAAType::kUnifiedMSAA != args.fRenderTargetContext->fsaaType());
3398acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    SkASSERT(!args.fShape->isEmpty());
3408c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    SkASSERT(!args.fShape->style().pathEffect());
341ecbc12b1c1c72de0cf7bba4a3f6a7cce4f43bf41csmartdalton
3420432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkPath path;
3430432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    args.fShape->asPath(&path);
3448acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    bool fill = args.fShape->style().isSimpleFill();
3458acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon    const SkStrokeRec& stroke = args.fShape->style().strokeRec();
3460432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth();
3470432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin();
3480432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkScalar miterLimit = stroke.getMiter();
3491a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
350b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    std::unique_ptr<GrDrawOp> op = AAFlatteningConvexPathOp::Make(
351b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon            std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth, stroke.getStyle(), join,
352b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon            miterLimit, args.fUserStencilSettings);
353b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
3541a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas    return true;
3551a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas}
3561a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
3571a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas///////////////////////////////////////////////////////////////////////////////////////////////////
3581a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
3596f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#if GR_TEST_UTILS
3601a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
361b295573c93e7a9a78ee736a399c256d7669b79beBrian SalomonGR_DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) {
362780dad1ab9469828e3ef317ad9aea12f9c0a270aBrian Salomon    SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
3630432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkPath path = GrTest::TestPathConvex(random);
3648c170971f182d47bc9af71fc88a607740d03dfd5robertphillips
3658c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    SkStrokeRec::Style styles[3] = { SkStrokeRec::kFill_Style,
36660c05f98aa22d89e4ef25acb4799936f5df3cff2Herb Derby                                     SkStrokeRec::kStroke_Style,
3678c170971f182d47bc9af71fc88a607740d03dfd5robertphillips                                     SkStrokeRec::kStrokeAndFill_Style };
3688c170971f182d47bc9af71fc88a607740d03dfd5robertphillips
3698c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    SkStrokeRec::Style style = styles[random->nextU() % 3];
3708c170971f182d47bc9af71fc88a607740d03dfd5robertphillips
3718c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    SkScalar strokeWidth = -1.f;
3720432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkPaint::Join join = SkPaint::kMiter_Join;
3730432dd6ee62d0c1c1ca67b7f6f6fcf3de75aaf77bsalomon    SkScalar miterLimit = 0.5f;
3748c170971f182d47bc9af71fc88a607740d03dfd5robertphillips
3758c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    if (SkStrokeRec::kFill_Style != style) {
3768c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        strokeWidth = random->nextRangeF(1.0f, 10.0f);
3778c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        if (random->nextBool()) {
3788c170971f182d47bc9af71fc88a607740d03dfd5robertphillips            join = SkPaint::kMiter_Join;
3798c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        } else {
3808c170971f182d47bc9af71fc88a607740d03dfd5robertphillips            join = SkPaint::kBevel_Join;
3818c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        }
3828c170971f182d47bc9af71fc88a607740d03dfd5robertphillips        miterLimit = random->nextRangeF(0.5f, 2.0f);
3838c170971f182d47bc9af71fc88a607740d03dfd5robertphillips    }
384b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context);
385b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon    return AAFlatteningConvexPathOp::Make(std::move(paint), viewMatrix, path, strokeWidth, style,
386b295573c93e7a9a78ee736a399c256d7669b79beBrian Salomon                                          join, miterLimit, stencilSettings);
3871a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas}
3881a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas
3891a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#endif
390