GrOvalOpFactory.cpp revision 11bf8b2eae7d1780cb969146422a2ab3b933047a
181312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org/*
281312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org * Copyright 2013 Google Inc.
381312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org *
481312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be
581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org * found in the LICENSE file.
681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org */
781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
881312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org#include "GrOvalRenderer.h"
981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
107539856c1b9cbb1886a6a498cc534b77fc83ddb2bsalomon#include "GrBatchFlushState.h"
113e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt#include "GrBatchTest.h"
12eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "GrGeometryProcessor.h"
13605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdaniel#include "GrInvariantOutput.h"
1476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt#include "GrProcessor.h"
15ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon#include "GrResourceProvider.h"
16f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org#include "SkRRect.h"
1781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org#include "SkStrokeRec.h"
1816b991390bb988b194a868ab8de66db4c21c7c13bsalomon#include "batches/GrVertexBatch.h"
192d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel#include "glsl/GrGLSLFragmentShaderBuilder.h"
20e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel#include "glsl/GrGLSLGeometryProcessor.h"
21018fb62d12d1febf121fe265da5b6117b86a6541egdaniel#include "glsl/GrGLSLProgramDataManager.h"
220eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel#include "glsl/GrGLSLVarying.h"
232d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel#include "glsl/GrGLSLVertexShaderBuilder.h"
247ea439b2203855db97330b25945b87dd4b170b8begdaniel#include "glsl/GrGLSLUniformHandler.h"
2564c4728c70001ed074fecf5c4e083781987b12e9egdaniel#include "glsl/GrGLSLUtil.h"
26234d4fba75aac009e34c088037fcd9e244798c40commit-bot@chromium.org
2776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt// TODO(joshualitt) - Break this file up during GrBatch post implementation cleanup
2876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orgnamespace {
30bb2ff94e223014403f775c3532a25cc25b00c949brianosman
3181312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orgstruct CircleVertex {
32972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fPos;
33bb2ff94e223014403f775c3532a25cc25b00c949brianosman    GrColor  fColor;
34972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fOffset;
3581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    SkScalar fOuterRadius;
3681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    SkScalar fInnerRadius;
3781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org};
3881312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
3981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orgstruct EllipseVertex {
40972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fPos;
41bb2ff94e223014403f775c3532a25cc25b00c949brianosman    GrColor  fColor;
42972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fOffset;
43972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fOuterRadii;
44972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fInnerRadii;
45f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org};
46f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
475242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.orgstruct DIEllipseVertex {
48972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fPos;
49bb2ff94e223014403f775c3532a25cc25b00c949brianosman    GrColor  fColor;
50972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fOuterOffset;
51972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fInnerOffset;
525242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org};
535242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5481312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orginline bool circle_stays_circle(const SkMatrix& m) {
5581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    return m.isSimilarity();
5681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org}
5781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
5881312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org}
5981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
6090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
6190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
6290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/**
63ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon * The output of this effect is a modulation of the input color and coverage for a circle. It
64ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon * operates in a space normalized by the circle radius (outer radius in the case of a stroke)
65cdaa97bf664e0d584187efc125bfff670a064a9absalomon * with origin at the circle center. Three vertex attributes are used:
66ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *    vec2f : position in device space of the bounding geometry vertices
67cdaa97bf664e0d584187efc125bfff670a064a9absalomon *    vec4ub: color
68ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *    vec4f : (p.xy, outerRad, innerRad)
69ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *             p is the position in the normalized space.
70ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *             outerRad is the outerRadius in device space.
71ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *             innerRad is the innerRadius in normalized space (ignored if not stroking).
7290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */
7390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
74cdaa97bf664e0d584187efc125bfff670a064a9absalomonclass CircleGeometryProcessor : public GrGeometryProcessor {
7590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic:
76cdaa97bf664e0d584187efc125bfff670a064a9absalomon    CircleGeometryProcessor(bool stroke, const SkMatrix& localMatrix) : fLocalMatrix(localMatrix){
77cdaa97bf664e0d584187efc125bfff670a064a9absalomon        this->initClassID<CircleGeometryProcessor>();
78cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
79cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                       kHigh_GrSLPrecision));
80cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
81cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInCircleEdge = &this->addVertexAttrib(Attribute("inCircleEdge",
82cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                         kVec4f_GrVertexAttribType));
83cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fStroke = stroke;
8490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
8590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
8671c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inPosition() const { return fInPosition; }
87bb2ff94e223014403f775c3532a25cc25b00c949brianosman    const Attribute* inColor() const { return fInColor; }
8871c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inCircleEdge() const { return fInCircleEdge; }
89e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    const SkMatrix& localMatrix() const { return fLocalMatrix; }
90cdaa97bf664e0d584187efc125bfff670a064a9absalomon    virtual ~CircleGeometryProcessor() {}
9190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
9236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "CircleEdge"; }
9390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
9457d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    class GLSLProcessor : public GrGLSLGeometryProcessor {
9590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    public:
96bb2ff94e223014403f775c3532a25cc25b00c949brianosman        GLSLProcessor() {}
9790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
9836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
99cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const CircleGeometryProcessor& cgp = args.fGP.cast<CircleGeometryProcessor>();
1004ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
1010eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
1027ea439b2203855db97330b25945b87dd4b170b8begdaniel            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1032dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
104abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit attributes
105cdaa97bf664e0d584187efc125bfff670a064a9absalomon            varyingHandler->emitAttributes(cgp);
106abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
1078dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel            GrGLSLVertToFrag v(kVec4f_GrSLType);
1080eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            varyingHandler->addVarying("CircleEdge", &v);
109cdaa97bf664e0d584187efc125bfff670a064a9absalomon            vertBuilder->codeAppendf("%s = %s;", v.vsOut(), cgp.inCircleEdge()->fName);
11090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
1118528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton            GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
112b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            // setup pass through color
113cdaa97bf664e0d584187efc125bfff670a064a9absalomon            varyingHandler->addPassThroughAttribute(cgp.inColor(), args.fOutputColor);
1149b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
115abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // Setup position
116cdaa97bf664e0d584187efc125bfff670a064a9absalomon            this->setupPosition(vertBuilder, gpArgs, cgp.inPosition()->fName);
117abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
118abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit transforms
1197ea439b2203855db97330b25945b87dd4b170b8begdaniel            this->emitTransforms(vertBuilder,
1200eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel                                 varyingHandler,
1217ea439b2203855db97330b25945b87dd4b170b8begdaniel                                 uniformHandler,
1224ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 gpArgs->fPositionVar,
123cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                 cgp.inPosition()->fName,
124cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                 cgp.localMatrix(),
1254ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 args.fTransformsIn,
1264ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 args.fTransformsOut);
1274ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
1284ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn());
1294ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("float edgeAlpha = clamp(%s.z * (1.0 - d), 0.0, 1.0);",
1304ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                     v.fsIn());
131cdaa97bf664e0d584187efc125bfff670a064a9absalomon            if (cgp.fStroke) {
1324ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("float innerAlpha = clamp(%s.z * (d - %s.w), 0.0, 1.0);",
1334ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         v.fsIn(), v.fsIn());
1344ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("edgeAlpha *= innerAlpha;");
13590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            }
1360a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org
1374ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
13890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
13990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
14046d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        static void GenKey(const GrGeometryProcessor& gp,
141cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                           const GrGLSLCaps&,
142b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                           GrProcessorKeyBuilder* b) {
143cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const CircleGeometryProcessor& cgp = gp.cast<CircleGeometryProcessor>();
144cdaa97bf664e0d584187efc125bfff670a064a9absalomon            uint16_t key = cgp.fStroke ? 0x1 : 0x0;
145cdaa97bf664e0d584187efc125bfff670a064a9absalomon            key |= cgp.localMatrix().hasPerspective() ? 0x2 : 0x0;
146b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            b->add32(key);
14790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
14890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
149018fb62d12d1febf121fe265da5b6117b86a6541egdaniel        void setData(const GrGLSLProgramDataManager& pdman,
150018fb62d12d1febf121fe265da5b6117b86a6541egdaniel                     const GrPrimitiveProcessor& gp) override {
1519b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        }
15290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
153e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        void setTransformData(const GrPrimitiveProcessor& primProc,
154018fb62d12d1febf121fe265da5b6117b86a6541egdaniel                              const GrGLSLProgramDataManager& pdman,
155e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              int index,
156e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
157cdaa97bf664e0d584187efc125bfff670a064a9absalomon            this->setTransformDataHelper<CircleGeometryProcessor>(primProc, pdman, index,
158cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                                  transforms);
159e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        }
160e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt
16190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    private:
162e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel        typedef GrGLSLGeometryProcessor INHERITED;
16390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    };
16490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
16557d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
16657d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel        GLSLProcessor::GenKey(*this, caps, b);
167eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
168eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
16957d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
17057d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel        return new GLSLProcessor();
171eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
17290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
17390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgprivate:
174cdaa97bf664e0d584187efc125bfff670a064a9absalomon    SkMatrix         fLocalMatrix;
17571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInPosition;
176bb2ff94e223014403f775c3532a25cc25b00c949brianosman    const Attribute* fInColor;
17771c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInCircleEdge;
178cdaa97bf664e0d584187efc125bfff670a064a9absalomon    bool             fStroke;
17990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
180b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
18190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
182249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGeometryProcessor INHERITED;
18390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org};
18490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
185cdaa97bf664e0d584187efc125bfff670a064a9absalomonGR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleGeometryProcessor);
18690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
18706ca8ec87cf6fab57cadd043a5ac18c4154a4129bungemansk_sp<GrGeometryProcessor> CircleGeometryProcessor::TestCreate(GrProcessorTestData* d) {
18806ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman    return sk_sp<GrGeometryProcessor>(
18906ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman        new CircleGeometryProcessor(d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom)));
19090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}
19190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
19290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
19390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
19490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/**
19590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * The output of this effect is a modulation of the input color and coverage for an axis-aligned
1968be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii,
1978be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com * in both x and y directions.
1988be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com *
1996bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
20090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */
20190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
202cdaa97bf664e0d584187efc125bfff670a064a9absalomonclass EllipseGeometryProcessor : public GrGeometryProcessor {
20390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic:
204cdaa97bf664e0d584187efc125bfff670a064a9absalomon    EllipseGeometryProcessor(bool stroke, const SkMatrix& localMatrix)
205cdaa97bf664e0d584187efc125bfff670a064a9absalomon        : fLocalMatrix(localMatrix) {
206cdaa97bf664e0d584187efc125bfff670a064a9absalomon        this->initClassID<EllipseGeometryProcessor>();
207cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
208cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
209cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInEllipseOffset = &this->addVertexAttrib(Attribute("inEllipseOffset",
210cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                            kVec2f_GrVertexAttribType));
211cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInEllipseRadii = &this->addVertexAttrib(Attribute("inEllipseRadii",
212cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                           kVec4f_GrVertexAttribType));
213cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fStroke = stroke;
21490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
21590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
216cdaa97bf664e0d584187efc125bfff670a064a9absalomon    virtual ~EllipseGeometryProcessor() {}
21790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
21836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "EllipseEdge"; }
2192dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
22071c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inPosition() const { return fInPosition; }
221bb2ff94e223014403f775c3532a25cc25b00c949brianosman    const Attribute* inColor() const { return fInColor; }
22271c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inEllipseOffset() const { return fInEllipseOffset; }
22371c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inEllipseRadii() const { return fInEllipseRadii; }
224e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    const SkMatrix& localMatrix() const { return fLocalMatrix; }
22590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
22657d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    class GLSLProcessor : public GrGLSLGeometryProcessor {
22790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    public:
228bb2ff94e223014403f775c3532a25cc25b00c949brianosman        GLSLProcessor() {}
22990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
23036352bf5e38f45a70ee4f4fc132a38048d38206dmtklein        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
231cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const EllipseGeometryProcessor& egp = args.fGP.cast<EllipseGeometryProcessor>();
2324ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
2330eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
2347ea439b2203855db97330b25945b87dd4b170b8begdaniel            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
23590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
236abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit attributes
237cdaa97bf664e0d584187efc125bfff670a064a9absalomon            varyingHandler->emitAttributes(egp);
238abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
2398dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel            GrGLSLVertToFrag ellipseOffsets(kVec2f_GrSLType);
2400eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            varyingHandler->addVarying("EllipseOffsets", &ellipseOffsets);
2414ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            vertBuilder->codeAppendf("%s = %s;", ellipseOffsets.vsOut(),
242cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                     egp.inEllipseOffset()->fName);
24390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
2448dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel            GrGLSLVertToFrag ellipseRadii(kVec4f_GrSLType);
2450eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            varyingHandler->addVarying("EllipseRadii", &ellipseRadii);
2464ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            vertBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(),
247cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                     egp.inEllipseRadii()->fName);
2482dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
2498528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton            GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
250b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            // setup pass through color
251cdaa97bf664e0d584187efc125bfff670a064a9absalomon            varyingHandler->addPassThroughAttribute(egp.inColor(), args.fOutputColor);
2529b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
253abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // Setup position
254cdaa97bf664e0d584187efc125bfff670a064a9absalomon            this->setupPosition(vertBuilder, gpArgs, egp.inPosition()->fName);
255abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
256abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit transforms
2577ea439b2203855db97330b25945b87dd4b170b8begdaniel            this->emitTransforms(vertBuilder,
2580eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel                                 varyingHandler,
2597ea439b2203855db97330b25945b87dd4b170b8begdaniel                                 uniformHandler,
2604ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 gpArgs->fPositionVar,
261cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                 egp.inPosition()->fName,
262cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                 egp.localMatrix(),
2634ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 args.fTransformsIn,
2644ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 args.fTransformsOut);
2654973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
2668be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com            // for outer curve
2674ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 scaledOffset = %s*%s.xy;", ellipseOffsets.fsIn(),
2684ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                     ellipseRadii.fsIn());
2694ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
2704ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 grad = 2.0*scaledOffset*%s.xy;", ellipseRadii.fsIn());
2714ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
27274077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt
2731b035d82d2b8b50ae334463edd06e4c5e0639311commit-bot@chromium.org            // avoid calling inversesqrt on zero.
2744ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
2754ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
276c6052ac41a704cc64f16c49780a8fd05c7f550d4brianosman            fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
277f58d8540a42e5138e7cdb1dd1e0b4de0fa3c4a10jvanverth@google.com
2786bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            // for inner curve
279cdaa97bf664e0d584187efc125bfff670a064a9absalomon            if (egp.fStroke) {
2804ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("scaledOffset = %s*%s.zw;",
2814ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         ellipseOffsets.fsIn(), ellipseRadii.fsIn());
2824ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
2834ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;",
2844ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         ellipseRadii.fsIn());
2854ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
2864ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
28790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            }
28890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
2894ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
29090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
29190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
29246d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        static void GenKey(const GrGeometryProcessor& gp,
293cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                           const GrGLSLCaps&,
294b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                           GrProcessorKeyBuilder* b) {
295cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const EllipseGeometryProcessor& egp = gp.cast<EllipseGeometryProcessor>();
296cdaa97bf664e0d584187efc125bfff670a064a9absalomon            uint16_t key = egp.fStroke ? 0x1 : 0x0;
297cdaa97bf664e0d584187efc125bfff670a064a9absalomon            key |= egp.localMatrix().hasPerspective() ? 0x2 : 0x0;
298b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            b->add32(key);
29990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
30090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
301018fb62d12d1febf121fe265da5b6117b86a6541egdaniel        void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp) override {
30290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
30390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
304e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        void setTransformData(const GrPrimitiveProcessor& primProc,
305018fb62d12d1febf121fe265da5b6117b86a6541egdaniel                              const GrGLSLProgramDataManager& pdman,
306e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              int index,
307e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
308cdaa97bf664e0d584187efc125bfff670a064a9absalomon            this->setTransformDataHelper<EllipseGeometryProcessor>(primProc, pdman, index,
309cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                                   transforms);
310e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        }
311e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt
31290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    private:
313e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel        typedef GrGLSLGeometryProcessor INHERITED;
31490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    };
31590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
31657d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
31757d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel        GLSLProcessor::GenKey(*this, caps, b);
318eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
319eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
32057d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
32157d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel        return new GLSLProcessor();
322eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
323eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
32490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgprivate:
32571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInPosition;
326bb2ff94e223014403f775c3532a25cc25b00c949brianosman    const Attribute* fInColor;
32771c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseOffset;
32871c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseRadii;
329e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    SkMatrix fLocalMatrix;
33090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    bool fStroke;
33190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
332b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
33390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
334249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGeometryProcessor INHERITED;
33590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org};
33690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
337cdaa97bf664e0d584187efc125bfff670a064a9absalomonGR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseGeometryProcessor);
33890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
33906ca8ec87cf6fab57cadd043a5ac18c4154a4129bungemansk_sp<GrGeometryProcessor> EllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) {
34006ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman    return sk_sp<GrGeometryProcessor>(
34106ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman        new EllipseGeometryProcessor(d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom)));
34290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}
34390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
34490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
34590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
3465242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org/**
3476fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.com * The output of this effect is a modulation of the input color and coverage for an ellipse,
3485242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * specified as a 2D offset from center for both the outer and inner paths (if stroked). The
3495242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge corrected by
3505242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * using differentials.
3515242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org *
3525242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * The result is device-independent and can be used with any affine matrix.
3535242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org */
3545242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
355cdaa97bf664e0d584187efc125bfff670a064a9absalomonenum class DIEllipseStyle { kStroke = 0, kHairline, kFill };
3565242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
357cdaa97bf664e0d584187efc125bfff670a064a9absalomonclass DIEllipseGeometryProcessor : public GrGeometryProcessor {
358cdaa97bf664e0d584187efc125bfff670a064a9absalomonpublic:
359cdaa97bf664e0d584187efc125bfff670a064a9absalomon    DIEllipseGeometryProcessor(const SkMatrix& viewMatrix, DIEllipseStyle style)
360cdaa97bf664e0d584187efc125bfff670a064a9absalomon        : fViewMatrix(viewMatrix) {
361cdaa97bf664e0d584187efc125bfff670a064a9absalomon        this->initClassID<DIEllipseGeometryProcessor>();
362cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
363cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                       kHigh_GrSLPrecision));
364cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
365cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInEllipseOffsets0 = &this->addVertexAttrib(Attribute("inEllipseOffsets0",
366cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                              kVec2f_GrVertexAttribType));
367cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fInEllipseOffsets1 = &this->addVertexAttrib(Attribute("inEllipseOffsets1",
368cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                              kVec2f_GrVertexAttribType));
369cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fStyle = style;
3705242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    }
3715242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
372cdaa97bf664e0d584187efc125bfff670a064a9absalomon
373cdaa97bf664e0d584187efc125bfff670a064a9absalomon    virtual ~DIEllipseGeometryProcessor() {}
3745242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
37536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "DIEllipseEdge"; }
3765242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
37771c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inPosition() const { return fInPosition; }
378bb2ff94e223014403f775c3532a25cc25b00c949brianosman    const Attribute* inColor() const { return fInColor; }
37971c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inEllipseOffsets0() const { return fInEllipseOffsets0; }
38071c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inEllipseOffsets1() const { return fInEllipseOffsets1; }
381e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt    const SkMatrix& viewMatrix() const { return fViewMatrix; }
3829d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
38357d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    class GLSLProcessor : public GrGLSLGeometryProcessor {
3845242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    public:
38557d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel        GLSLProcessor()
386bb2ff94e223014403f775c3532a25cc25b00c949brianosman            : fViewMatrix(SkMatrix::InvalidMatrix()) {}
3875242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
388465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
389cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const DIEllipseGeometryProcessor& diegp = args.fGP.cast<DIEllipseGeometryProcessor>();
3904ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
3910eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
3927ea439b2203855db97330b25945b87dd4b170b8begdaniel            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
3935242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
394abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit attributes
395cdaa97bf664e0d584187efc125bfff670a064a9absalomon            varyingHandler->emitAttributes(diegp);
396abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
3978dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel            GrGLSLVertToFrag offsets0(kVec2f_GrSLType);
3980eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            varyingHandler->addVarying("EllipseOffsets0", &offsets0);
3994ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            vertBuilder->codeAppendf("%s = %s;", offsets0.vsOut(),
400cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                     diegp.inEllipseOffsets0()->fName);
40174077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt
4028dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel            GrGLSLVertToFrag offsets1(kVec2f_GrSLType);
4030eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            varyingHandler->addVarying("EllipseOffsets1", &offsets1);
4044ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            vertBuilder->codeAppendf("%s = %s;", offsets1.vsOut(),
405cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                     diegp.inEllipseOffsets1()->fName);
4062dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
4078528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton            GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
408cdaa97bf664e0d584187efc125bfff670a064a9absalomon            varyingHandler->addPassThroughAttribute(diegp.inColor(), args.fOutputColor);
4099b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
410abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // Setup position
4117ea439b2203855db97330b25945b87dd4b170b8begdaniel            this->setupPosition(vertBuilder,
4127ea439b2203855db97330b25945b87dd4b170b8begdaniel                                uniformHandler,
4134ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                gpArgs,
414cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                diegp.inPosition()->fName,
415cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                diegp.viewMatrix(),
4165559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt                                &fViewMatrixUniform);
417abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
418abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit transforms
4197ea439b2203855db97330b25945b87dd4b170b8begdaniel            this->emitTransforms(vertBuilder,
4200eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel                                 varyingHandler,
4217ea439b2203855db97330b25945b87dd4b170b8begdaniel                                 uniformHandler,
4224ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 gpArgs->fPositionVar,
423cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                 diegp.inPosition()->fName,
4244ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 args.fTransformsIn,
4254ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 args.fTransformsOut);
4264ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
4274ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            SkAssertResult(fragBuilder->enableFeature(
4282d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                    GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
4295242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            // for outer curve
4304ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 scaledOffset = %s.xy;", offsets0.fsIn());
4314ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
4324ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s);", offsets0.fsIn());
4334ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s);", offsets0.fsIn());
4344ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
4354ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                     "                 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
436cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                     offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(),
437cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                     offsets0.fsIn());
4384ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
4394ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
4401b035d82d2b8b50ae334463edd06e4c5e0639311commit-bot@chromium.org            // avoid calling inversesqrt on zero.
4414ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
4424ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
443cdaa97bf664e0d584187efc125bfff670a064a9absalomon            if (DIEllipseStyle::kHairline == diegp.fStyle) {
4445242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org                // can probably do this with one step
4454ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("float edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);");
4464ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("edgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);");
4475242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            } else {
4484ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
4495242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            }
4505242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
4515242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            // for inner curve
452cdaa97bf664e0d584187efc125bfff670a064a9absalomon            if (DIEllipseStyle::kStroke == diegp.fStyle) {
4534ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("scaledOffset = %s.xy;", offsets1.fsIn());
4544ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
4554ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("duvdx = dFdx(%s);", offsets1.fsIn());
4564ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("duvdy = dFdy(%s);", offsets1.fsIn());
4574ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
4584ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         "            2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
4594ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(),
4604ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         offsets1.fsIn());
4614ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
4624ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
4635242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            }
4645242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
4654ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
4665242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
4675242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
46846d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        static void GenKey(const GrGeometryProcessor& gp,
469cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                           const GrGLSLCaps&,
470b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                           GrProcessorKeyBuilder* b) {
471cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const DIEllipseGeometryProcessor& diegp = gp.cast<DIEllipseGeometryProcessor>();
472cdaa97bf664e0d584187efc125bfff670a064a9absalomon            uint16_t key = static_cast<uint16_t>(diegp.fStyle);
473cdaa97bf664e0d584187efc125bfff670a064a9absalomon            key |= ComputePosKey(diegp.viewMatrix()) << 10;
474b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            b->add32(key);
4755242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
4765242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
477018fb62d12d1febf121fe265da5b6117b86a6541egdaniel        void setData(const GrGLSLProgramDataManager& pdman,
478018fb62d12d1febf121fe265da5b6117b86a6541egdaniel                     const GrPrimitiveProcessor& gp) override {
479cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const DIEllipseGeometryProcessor& diegp = gp.cast<DIEllipseGeometryProcessor>();
4805559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt
481cdaa97bf664e0d584187efc125bfff670a064a9absalomon            if (!diegp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(diegp.viewMatrix())) {
482cdaa97bf664e0d584187efc125bfff670a064a9absalomon                fViewMatrix = diegp.viewMatrix();
483018fb62d12d1febf121fe265da5b6117b86a6541egdaniel                float viewMatrix[3 * 3];
48464c4728c70001ed074fecf5c4e083781987b12e9egdaniel                GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
4855559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt                pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
4865559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt            }
4875242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
4885242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
4895242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    private:
4905559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        SkMatrix fViewMatrix;
4915559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        UniformHandle fViewMatrixUniform;
4929b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
493e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel        typedef GrGLSLGeometryProcessor INHERITED;
4945242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    };
4955242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
49657d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
49757d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel        GLSLProcessor::GenKey(*this, caps, b);
498eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
499eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
50057d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
50157d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel        return new GLSLProcessor();
502eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
503eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
5045242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.orgprivate:
50571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInPosition;
506bb2ff94e223014403f775c3532a25cc25b00c949brianosman    const Attribute* fInColor;
50771c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseOffsets0;
50871c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseOffsets1;
509cdaa97bf664e0d584187efc125bfff670a064a9absalomon    SkMatrix         fViewMatrix;
510cdaa97bf664e0d584187efc125bfff670a064a9absalomon    DIEllipseStyle   fStyle;
5115242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
512b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
5135242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
514249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGeometryProcessor INHERITED;
5155242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org};
5165242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
517cdaa97bf664e0d584187efc125bfff670a064a9absalomonGR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseGeometryProcessor);
5185242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
51906ca8ec87cf6fab57cadd043a5ac18c4154a4129bungemansk_sp<GrGeometryProcessor> DIEllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) {
52006ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman    return sk_sp<GrGeometryProcessor>(
52106ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman        new DIEllipseGeometryProcessor(GrTest::TestMatrix(d->fRandom),
52206ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman                                       (DIEllipseStyle)(d->fRandom->nextRangeU(0,2))));
5235242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org}
5245242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5255242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
5265242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
52711bf8b2eae7d1780cb969146422a2ab3b933047absalomonclass CircleBatch : public GrVertexBatch {
52811bf8b2eae7d1780cb969146422a2ab3b933047absalomonpublic:
52911bf8b2eae7d1780cb969146422a2ab3b933047absalomon    DEFINE_BATCH_CLASS_ID
53081312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
53111bf8b2eae7d1780cb969146422a2ab3b933047absalomon    CircleBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& circle,
53211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                const SkStrokeRec& stroke)
53311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            : INHERITED(ClassID())
53411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            , fViewMatrixIfUsingLocalCoords(viewMatrix) {
53511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
53611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        viewMatrix.mapPoints(&center, 1);
53711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
53811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
539f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
54011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkStrokeRec::Style style = stroke.getStyle();
54111bf8b2eae7d1780cb969146422a2ab3b933047absalomon        bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
54211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                            SkStrokeRec::kHairline_Style == style;
54311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
5441b55a963a2374a14bb82eb887bb99ee91680f0ebreed
54511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar innerRadius = 0.0f;
54611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar outerRadius = radius;
54711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar halfWidth = 0;
54811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        if (hasStroke) {
54911bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (SkScalarNearlyZero(strokeWidth)) {
55011bf8b2eae7d1780cb969146422a2ab3b933047absalomon                halfWidth = SK_ScalarHalf;
55111bf8b2eae7d1780cb969146422a2ab3b933047absalomon            } else {
55211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                halfWidth = SkScalarHalf(strokeWidth);
55311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
55476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
55511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            outerRadius += halfWidth;
55611bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (isStrokeOnly) {
55711bf8b2eae7d1780cb969146422a2ab3b933047absalomon                innerRadius = radius - halfWidth;
55811bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
55911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        }
5605fd209e8ee477c703bc5c11b008f247d515fc0fcbsalomon
56111bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // The radii are outset for two reasons. First, it allows the shader to simply perform
56211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
56311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // Second, the outer radius is used to compute the verts of the bounding box that is
56411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // rendered and the outset ensures the box will cover all partially covered by the circle.
56511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        outerRadius += SK_ScalarHalf;
56611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        innerRadius -= SK_ScalarHalf;
5677f06c6947a3bef78dc57b9252779567c33604c90bsalomon
56811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        fGeoData.emplace_back(Geometry {
56911bf8b2eae7d1780cb969146422a2ab3b933047absalomon            color,
57011bf8b2eae7d1780cb969146422a2ab3b933047absalomon            innerRadius,
57111bf8b2eae7d1780cb969146422a2ab3b933047absalomon            outerRadius,
57211bf8b2eae7d1780cb969146422a2ab3b933047absalomon            SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
57311bf8b2eae7d1780cb969146422a2ab3b933047absalomon                             center.fX + outerRadius, center.fY + outerRadius)
57411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        });
57511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        this->setBounds(fGeoData.back().fDevBounds);
57611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        fStroked = isStrokeOnly && innerRadius > 0;
577df4f47b8ff6378c4d8f775dcb3169ac7c64f2510benjaminwagner    }
57811bf8b2eae7d1780cb969146422a2ab3b933047absalomon
57936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "CircleBatch"; }
58076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
581e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips    SkString dumpInfo() const override {
582e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        SkString string;
583e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        for (int i = 0; i < fGeoData.count(); ++i) {
584e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips            string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
585e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips                           "InnerRad: %.2f, OuterRad: %.2f\n",
586e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips                           fGeoData[i].fColor,
587e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips                           fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
588e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips                           fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
589e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips                           fGeoData[i].fInnerRadius,
590e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips                           fGeoData[i].fOuterRadius);
591e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        }
592e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        string.append(INHERITED::dumpInfo());
593e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        return string;
594e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips    }
595e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips
5969d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary    void computePipelineOptimizations(GrInitInvariantOutput* color,
597ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrInitInvariantOutput* coverage,
598ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrBatchToXPOverrides* overrides) const override {
59976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
600ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        color->setKnownFourComponents(fGeoData[0].fColor);
601ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        coverage->setUnknownSingleComponent();
60276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
60376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
604e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomonprivate:
605ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas    void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
606cdaa97bf664e0d584187efc125bfff670a064a9absalomon        // Handle any overrides that affect our GP.
607ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
608cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!overrides.readsLocalCoords()) {
609cdaa97bf664e0d584187efc125bfff670a064a9absalomon            fViewMatrixIfUsingLocalCoords.reset();
610cdaa97bf664e0d584187efc125bfff670a064a9absalomon        }
61176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
61276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
613144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
614cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkMatrix localMatrix;
615cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
61676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
61776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
61876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
61976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
620cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroked, localMatrix));
62176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
62276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
62376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
62476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(vertexStride == sizeof(CircleVertex));
625b5238a7571c243ba4a154a62575570c3078b3741bsalomon        QuadHelper helper;
6267539856c1b9cbb1886a6a498cc534b77fc83ddb2bsalomon        CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target, vertexStride,
627b5238a7571c243ba4a154a62575570c3078b3741bsalomon                                                                          instanceCount));
628b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts) {
6294b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
6304b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
6314b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
63276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
633144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& geom = fGeoData[i];
63476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
635bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = geom.fColor;
636b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar innerRadius = geom.fInnerRadius;
637b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar outerRadius = geom.fOuterRadius;
63876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
639b5238a7571c243ba4a154a62575570c3078b3741bsalomon            const SkRect& bounds = geom.fDevBounds;
64076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
64176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // The inner radius in the vertex data must be specified in normalized space.
64276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            innerRadius = innerRadius / outerRadius;
64376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
644bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[0].fColor = color;
64576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOffset = SkPoint::Make(-1, -1);
64676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOuterRadius = outerRadius;
64776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fInnerRadius = innerRadius;
64876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
64976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
650bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[1].fColor = color;
65176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOffset = SkPoint::Make(-1, 1);
65276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOuterRadius = outerRadius;
65376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fInnerRadius = innerRadius;
65476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
65576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
656bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[2].fColor = color;
65776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOffset = SkPoint::Make(1, 1);
65876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOuterRadius = outerRadius;
65976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fInnerRadius = innerRadius;
66076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
66176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
662bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[3].fColor = color;
66376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOffset = SkPoint::Make(1, -1);
66476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOuterRadius = outerRadius;
66576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fInnerRadius = innerRadius;
66676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
667b5238a7571c243ba4a154a62575570c3078b3741bsalomon            verts += kVerticesPerQuad;
66876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
669342bfc25de5b0452b1551bf9db4bf45eac7718b2bsalomon        helper.recordDraw(target, gp);
67076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
67176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
672cb02b38b2c48bfde333ce3c699dd0451e2d867fabsalomon    bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
673abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        CircleBatch* that = t->cast<CircleBatch>();
674abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
675abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
6768cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
6778cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
6788cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
679cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (this->fStroked != that->fStroked) {
68076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
68176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
68276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
683cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
68476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
68576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
68676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
687cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
68899c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
68976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
69076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
69176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
69211bf8b2eae7d1780cb969146422a2ab3b933047absalomon    struct Geometry {
69311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        GrColor fColor;
69411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fInnerRadius;
69511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fOuterRadius;
69611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkRect fDevBounds;
69711bf8b2eae7d1780cb969146422a2ab3b933047absalomon    };
69811bf8b2eae7d1780cb969146422a2ab3b933047absalomon
699cdaa97bf664e0d584187efc125bfff670a064a9absalomon    bool                         fStroked;
700cdaa97bf664e0d584187efc125bfff670a064a9absalomon    SkMatrix                     fViewMatrixIfUsingLocalCoords;
70176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
7021b55a963a2374a14bb82eb887bb99ee91680f0ebreed
7031b55a963a2374a14bb82eb887bb99ee91680f0ebreed    typedef GrVertexBatch INHERITED;
70476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
70576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
706f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
707f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
708abd30f54b7ff1704a8930c4307ea242d09425d02bsalomonclass EllipseBatch : public GrVertexBatch {
70976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
7101b55a963a2374a14bb82eb887bb99ee91680f0ebreed    DEFINE_BATCH_CLASS_ID
71111bf8b2eae7d1780cb969146422a2ab3b933047absalomon    static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& ellipse,
71211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                               const SkStrokeRec& stroke) {
71311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkASSERT(viewMatrix.rectStaysRect());
71411bf8b2eae7d1780cb969146422a2ab3b933047absalomon
71511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // do any matrix crunching before we reset the draw state for device coords
71611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
71711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        viewMatrix.mapPoints(&center, 1);
71811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
71911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
72011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius +
72111bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                       viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius);
72211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius +
72311bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                       viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius);
72411bf8b2eae7d1780cb969146422a2ab3b933047absalomon
72511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // do (potentially) anisotropic mapping of stroke
72611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkVector scaledStroke;
72711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar strokeWidth = stroke.getWidth();
72811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
72911bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                                   viewMatrix[SkMatrix::kMSkewY]));
73011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
73111bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                                   viewMatrix[SkMatrix::kMScaleY]));
73211bf8b2eae7d1780cb969146422a2ab3b933047absalomon
73311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkStrokeRec::Style style = stroke.getStyle();
73411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
73511bf8b2eae7d1780cb969146422a2ab3b933047absalomon                            SkStrokeRec::kHairline_Style == style;
73611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
73711bf8b2eae7d1780cb969146422a2ab3b933047absalomon
73811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar innerXRadius = 0;
73911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar innerYRadius = 0;
74011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        if (hasStroke) {
74111bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (SkScalarNearlyZero(scaledStroke.length())) {
74211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
74311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            } else {
74411bf8b2eae7d1780cb969146422a2ab3b933047absalomon                scaledStroke.scale(SK_ScalarHalf);
74511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
7465fd209e8ee477c703bc5c11b008f247d515fc0fcbsalomon
74711bf8b2eae7d1780cb969146422a2ab3b933047absalomon            // we only handle thick strokes for near-circular ellipses
74811bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (scaledStroke.length() > SK_ScalarHalf &&
74911bf8b2eae7d1780cb969146422a2ab3b933047absalomon                (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
75011bf8b2eae7d1780cb969146422a2ab3b933047absalomon                return nullptr;
75111bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
7527f06c6947a3bef78dc57b9252779567c33604c90bsalomon
75311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
75411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
75511bf8b2eae7d1780cb969146422a2ab3b933047absalomon                scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
75611bf8b2eae7d1780cb969146422a2ab3b933047absalomon                return nullptr;
75711bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
75811bf8b2eae7d1780cb969146422a2ab3b933047absalomon
75911bf8b2eae7d1780cb969146422a2ab3b933047absalomon            // this is legit only if scale & translation (which should be the case at the moment)
76011bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (isStrokeOnly) {
76111bf8b2eae7d1780cb969146422a2ab3b933047absalomon                innerXRadius = xRadius - scaledStroke.fX;
76211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                innerYRadius = yRadius - scaledStroke.fY;
76311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
76411bf8b2eae7d1780cb969146422a2ab3b933047absalomon
76511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            xRadius += scaledStroke.fX;
76611bf8b2eae7d1780cb969146422a2ab3b933047absalomon            yRadius += scaledStroke.fY;
76711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        }
76811bf8b2eae7d1780cb969146422a2ab3b933047absalomon
76911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        EllipseBatch* batch = new EllipseBatch();
77011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->fGeoData.emplace_back(Geometry {
77111bf8b2eae7d1780cb969146422a2ab3b933047absalomon            color,
77211bf8b2eae7d1780cb969146422a2ab3b933047absalomon            xRadius,
77311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            yRadius,
77411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            innerXRadius,
77511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            innerYRadius,
77611bf8b2eae7d1780cb969146422a2ab3b933047absalomon            SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius,
77711bf8b2eae7d1780cb969146422a2ab3b933047absalomon                             center.fX + xRadius, center.fY + yRadius)
77811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        });
77911bf8b2eae7d1780cb969146422a2ab3b933047absalomon
78011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // Outset bounds to include half-pixel width antialiasing.
78111bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->fGeoData[0].fDevBounds.outset(SK_ScalarHalf, SK_ScalarHalf);
78211bf8b2eae7d1780cb969146422a2ab3b933047absalomon
78311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->fStroked = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
78411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->fViewMatrixIfUsingLocalCoords = viewMatrix;
78511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->setBounds(batch->fGeoData.back().fDevBounds);
78611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        return batch;
787cdaa97bf664e0d584187efc125bfff670a064a9absalomon    }
78876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
78936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "EllipseBatch"; }
79076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
7919d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary    void computePipelineOptimizations(GrInitInvariantOutput* color,
792ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrInitInvariantOutput* coverage,
793ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrBatchToXPOverrides* overrides) const override {
79476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
795ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        color->setKnownFourComponents(fGeoData[0].fColor);
796ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        coverage->setUnknownSingleComponent();
79776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
79876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
799e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomonprivate:
80011bf8b2eae7d1780cb969146422a2ab3b933047absalomon    EllipseBatch() : INHERITED(ClassID()) {}
80111bf8b2eae7d1780cb969146422a2ab3b933047absalomon
802ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas    void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
803cdaa97bf664e0d584187efc125bfff670a064a9absalomon        // Handle any overrides that affect our GP.
804ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        if (!overrides.readsCoverage()) {
80576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = GrColor_ILLEGAL;
80676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
807cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!overrides.readsLocalCoords()) {
808cdaa97bf664e0d584187efc125bfff670a064a9absalomon            fViewMatrixIfUsingLocalCoords.reset();
809cdaa97bf664e0d584187efc125bfff670a064a9absalomon        }
81076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
81176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
812144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
813cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkMatrix localMatrix;
814cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
81576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
81676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
81776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
81876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
819cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkAutoTUnref<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
82076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
82176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
822b5238a7571c243ba4a154a62575570c3078b3741bsalomon        QuadHelper helper;
82376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
82419e0058a650a9e4dc9c35ed26c5e91916bcc0601joshualitt        SkASSERT(vertexStride == sizeof(EllipseVertex));
825b5238a7571c243ba4a154a62575570c3078b3741bsalomon        EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
8267539856c1b9cbb1886a6a498cc534b77fc83ddb2bsalomon            helper.init(target, vertexStride, instanceCount));
827b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts) {
8284b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
8294b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
8304b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
83176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
832144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& geom = fGeoData[i];
83376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
834bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = geom.fColor;
835b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar xRadius = geom.fXRadius;
836b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar yRadius = geom.fYRadius;
83776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
83876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // Compute the reciprocals of the radii here to save time in the shader
83976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xRadRecip = SkScalarInvert(xRadius);
84076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yRadRecip = SkScalarInvert(yRadius);
841b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar xInnerRadRecip = SkScalarInvert(geom.fInnerXRadius);
842b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar yInnerRadRecip = SkScalarInvert(geom.fInnerYRadius);
84376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
844b5238a7571c243ba4a154a62575570c3078b3741bsalomon            const SkRect& bounds = geom.fDevBounds;
84576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
846977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            // fOffsets are expanded from xyRadii to include the half-pixel antialiasing width.
847977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            SkScalar xMaxOffset = xRadius + SK_ScalarHalf;
848977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            SkScalar yMaxOffset = yRadius + SK_ScalarHalf;
849977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack
85076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // The inner radius in the vertex data must be specified in normalized space.
85176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
852bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[0].fColor = color;
853977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            verts[0].fOffset = SkPoint::Make(-xMaxOffset, -yMaxOffset);
85476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
85576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
85676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
85776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
858bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[1].fColor = color;
859977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            verts[1].fOffset = SkPoint::Make(-xMaxOffset, yMaxOffset);
86076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
86176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
86276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
86376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
864bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[2].fColor = color;
865977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            verts[2].fOffset = SkPoint::Make(xMaxOffset, yMaxOffset);
86676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
86776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
86876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
86976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
870bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[3].fColor = color;
871977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            verts[3].fOffset = SkPoint::Make(xMaxOffset, -yMaxOffset);
87276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
87376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
87476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
875b5238a7571c243ba4a154a62575570c3078b3741bsalomon            verts += kVerticesPerQuad;
87676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
877342bfc25de5b0452b1551bf9db4bf45eac7718b2bsalomon        helper.recordDraw(target, gp);
87876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
87976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
880cb02b38b2c48bfde333ce3c699dd0451e2d867fabsalomon    bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
881abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        EllipseBatch* that = t->cast<EllipseBatch>();
882abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon
883abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
884abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
8858cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
8868cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
8878cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
888cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (fStroked != that->fStroked) {
88976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
89076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
89176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
892cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
89376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
89476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
89576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
896cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
89799c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
89876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
89976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
90076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
90111bf8b2eae7d1780cb969146422a2ab3b933047absalomon    struct Geometry {
90211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        GrColor fColor;
90311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fXRadius;
90411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fYRadius;
90511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fInnerXRadius;
90611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fInnerYRadius;
90711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkRect fDevBounds;
90811bf8b2eae7d1780cb969146422a2ab3b933047absalomon    };
90976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
910cdaa97bf664e0d584187efc125bfff670a064a9absalomon    bool                         fStroked;
911cdaa97bf664e0d584187efc125bfff670a064a9absalomon    SkMatrix                     fViewMatrixIfUsingLocalCoords;
91276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
9131b55a963a2374a14bb82eb887bb99ee91680f0ebreed
9141b55a963a2374a14bb82eb887bb99ee91680f0ebreed    typedef GrVertexBatch INHERITED;
91576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
91676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
91711bf8b2eae7d1780cb969146422a2ab3b933047absalomon/////////////////////////////////////////////////////////////////////////////////////////////////
9186bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
91911bf8b2eae7d1780cb969146422a2ab3b933047absalomonclass DIEllipseBatch : public GrVertexBatch {
92011bf8b2eae7d1780cb969146422a2ab3b933047absalomonpublic:
92111bf8b2eae7d1780cb969146422a2ab3b933047absalomon    DEFINE_BATCH_CLASS_ID
9226bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
92311bf8b2eae7d1780cb969146422a2ab3b933047absalomon    static GrDrawBatch* Create(GrColor color,
92411bf8b2eae7d1780cb969146422a2ab3b933047absalomon                               const SkMatrix& viewMatrix,
92511bf8b2eae7d1780cb969146422a2ab3b933047absalomon                               const SkRect& ellipse,
92611bf8b2eae7d1780cb969146422a2ab3b933047absalomon                               const SkStrokeRec& stroke) {
92711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
92811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar xRadius = SkScalarHalf(ellipse.width());
92911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar yRadius = SkScalarHalf(ellipse.height());
93011bf8b2eae7d1780cb969146422a2ab3b933047absalomon
93111bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkStrokeRec::Style style = stroke.getStyle();
93211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        DIEllipseStyle dieStyle = (SkStrokeRec::kStroke_Style == style) ?
93311bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                  DIEllipseStyle::kStroke :
93411bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                  (SkStrokeRec::kHairline_Style == style) ?
93511bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                  DIEllipseStyle::kHairline : DIEllipseStyle::kFill;
93611bf8b2eae7d1780cb969146422a2ab3b933047absalomon
93711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar innerXRadius = 0;
93811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar innerYRadius = 0;
93911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
94011bf8b2eae7d1780cb969146422a2ab3b933047absalomon            SkScalar strokeWidth = stroke.getWidth();
94111bf8b2eae7d1780cb969146422a2ab3b933047absalomon
94211bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (SkScalarNearlyZero(strokeWidth)) {
94311bf8b2eae7d1780cb969146422a2ab3b933047absalomon                strokeWidth = SK_ScalarHalf;
94411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            } else {
94511bf8b2eae7d1780cb969146422a2ab3b933047absalomon                strokeWidth *= SK_ScalarHalf;
94611bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
9476bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
94811bf8b2eae7d1780cb969146422a2ab3b933047absalomon            // we only handle thick strokes for near-circular ellipses
94911bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (strokeWidth > SK_ScalarHalf &&
95011bf8b2eae7d1780cb969146422a2ab3b933047absalomon                (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
95111bf8b2eae7d1780cb969146422a2ab3b933047absalomon                return nullptr;
95211bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
9536bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
95411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
95511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
95611bf8b2eae7d1780cb969146422a2ab3b933047absalomon                strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
95711bf8b2eae7d1780cb969146422a2ab3b933047absalomon                return nullptr;
95811bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
959fc5b70a8e427ee115868786fa361c2c813ab566bbenjaminwagner
96011bf8b2eae7d1780cb969146422a2ab3b933047absalomon            // set inner radius (if needed)
96111bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (SkStrokeRec::kStroke_Style == style) {
96211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                innerXRadius = xRadius - strokeWidth;
96311bf8b2eae7d1780cb969146422a2ab3b933047absalomon                innerYRadius = yRadius - strokeWidth;
96411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
965df4f47b8ff6378c4d8f775dcb3169ac7c64f2510benjaminwagner
96611bf8b2eae7d1780cb969146422a2ab3b933047absalomon            xRadius += strokeWidth;
96711bf8b2eae7d1780cb969146422a2ab3b933047absalomon            yRadius += strokeWidth;
96811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        }
96911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        if (DIEllipseStyle::kStroke == dieStyle) {
97011bf8b2eae7d1780cb969146422a2ab3b933047absalomon            dieStyle = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseStyle ::kStroke :
97111bf8b2eae7d1780cb969146422a2ab3b933047absalomon                       DIEllipseStyle ::kFill;
9726bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        }
9736bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
97411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // This expands the outer rect so that after CTM we end up with a half-pixel border
97511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar a = viewMatrix[SkMatrix::kMScaleX];
97611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar b = viewMatrix[SkMatrix::kMSkewX];
97711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar c = viewMatrix[SkMatrix::kMSkewY];
97811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar d = viewMatrix[SkMatrix::kMScaleY];
97911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
98011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
98111bf8b2eae7d1780cb969146422a2ab3b933047absalomon
98211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        DIEllipseBatch* batch = new DIEllipseBatch();
98311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->fGeoData.emplace_back(Geometry {
98411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            viewMatrix,
98511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            color,
98611bf8b2eae7d1780cb969146422a2ab3b933047absalomon            xRadius,
98711bf8b2eae7d1780cb969146422a2ab3b933047absalomon            yRadius,
98811bf8b2eae7d1780cb969146422a2ab3b933047absalomon            innerXRadius,
98911bf8b2eae7d1780cb969146422a2ab3b933047absalomon            innerYRadius,
99011bf8b2eae7d1780cb969146422a2ab3b933047absalomon            geoDx,
99111bf8b2eae7d1780cb969146422a2ab3b933047absalomon            geoDy,
99211bf8b2eae7d1780cb969146422a2ab3b933047absalomon            dieStyle,
99311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
99411bf8b2eae7d1780cb969146422a2ab3b933047absalomon                             center.fX + xRadius + geoDx, center.fY + yRadius + geoDy)
99511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        });
99611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkRect devBounds = batch->fGeoData.back().fBounds;
99711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        viewMatrix.mapRect(&devBounds);
99811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->setBounds(devBounds);
99911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        return batch;
100076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
100176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
100236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "DIEllipseBatch"; }
100376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
10049d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary    void computePipelineOptimizations(GrInitInvariantOutput* color,
1005ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrInitInvariantOutput* coverage,
1006ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrBatchToXPOverrides* overrides) const override {
100776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
1008ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        color->setKnownFourComponents(fGeoData[0].fColor);
1009ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        coverage->setUnknownSingleComponent();
101076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
101176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1012e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomonprivate:
1013e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomon
101411bf8b2eae7d1780cb969146422a2ab3b933047absalomon    DIEllipseBatch() : INHERITED(ClassID()) {}
101511bf8b2eae7d1780cb969146422a2ab3b933047absalomon
1016ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas    void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1017cdaa97bf664e0d584187efc125bfff670a064a9absalomon        // Handle any overrides that affect our GP.
1018ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1019cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fUsesLocalCoords = overrides.readsLocalCoords();
102076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
102176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1022144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
102376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
1024cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkAutoTUnref<GrGeometryProcessor> gp(new DIEllipseGeometryProcessor(this->viewMatrix(),
1025cdaa97bf664e0d584187efc125bfff670a064a9absalomon                                                                            this->style()));
102676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
102776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
102876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
102919e0058a650a9e4dc9c35ed26c5e91916bcc0601joshualitt        SkASSERT(vertexStride == sizeof(DIEllipseVertex));
1030b5238a7571c243ba4a154a62575570c3078b3741bsalomon        QuadHelper helper;
1031b5238a7571c243ba4a154a62575570c3078b3741bsalomon        DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(
10327539856c1b9cbb1886a6a498cc534b77fc83ddb2bsalomon            helper.init(target, vertexStride, instanceCount));
1033b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts) {
10344b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
10354b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
10364b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
103776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
1038144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& geom = fGeoData[i];
103976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1040bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = geom.fColor;
1041b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar xRadius = geom.fXRadius;
1042b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar yRadius = geom.fYRadius;
104376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1044b5238a7571c243ba4a154a62575570c3078b3741bsalomon            const SkRect& bounds = geom.fBounds;
104576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
104676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // This adjusts the "radius" to include the half-pixel border
104780ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar offsetDx = geom.fGeoDx / xRadius;
104880ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar offsetDy = geom.fGeoDy / yRadius;
104976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
105080ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar innerRatioX = xRadius / geom.fInnerXRadius;
105180ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar innerRatioY = yRadius / geom.fInnerYRadius;
105276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
105376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
1054bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[0].fColor = color;
105576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
105676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
105776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
105876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
1059bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[1].fColor = color;
106076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
106176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
106276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
106376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
1064bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[2].fColor = color;
106576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
106676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
106776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
106876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1069bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[3].fColor = color;
107076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
107176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
107276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1073b5238a7571c243ba4a154a62575570c3078b3741bsalomon            verts += kVerticesPerQuad;
107476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
1075342bfc25de5b0452b1551bf9db4bf45eac7718b2bsalomon        helper.recordDraw(target, gp);
107676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
10779d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
1078cb02b38b2c48bfde333ce3c699dd0451e2d867fabsalomon    bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
1079abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        DIEllipseBatch* that = t->cast<DIEllipseBatch>();
1080abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1081abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
10828cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
10838cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
10848cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
1085cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (this->style() != that->style()) {
108676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
108776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
108876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1089d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        // TODO rewrite to allow positioning on CPU
1090d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
109176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
109276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
109376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1094cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
109599c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
109676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
109776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
109876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
109976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1100cdaa97bf664e0d584187efc125bfff670a064a9absalomon    DIEllipseStyle style() const { return fGeoData[0].fStyle; }
110176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
110211bf8b2eae7d1780cb969146422a2ab3b933047absalomon    struct Geometry {
110311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkMatrix fViewMatrix;
110411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        GrColor fColor;
110511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fXRadius;
110611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fYRadius;
110711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fInnerXRadius;
110811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fInnerYRadius;
110911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fGeoDx;
111011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fGeoDy;
111111bf8b2eae7d1780cb969146422a2ab3b933047absalomon        DIEllipseStyle fStyle;
111211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkRect fBounds;
111311bf8b2eae7d1780cb969146422a2ab3b933047absalomon    };
111411bf8b2eae7d1780cb969146422a2ab3b933047absalomon
1115cdaa97bf664e0d584187efc125bfff670a064a9absalomon    bool                         fUsesLocalCoords;
111676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
11171b55a963a2374a14bb82eb887bb99ee91680f0ebreed
11181b55a963a2374a14bb82eb887bb99ee91680f0ebreed    typedef GrVertexBatch INHERITED;
111976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
1120f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1121f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
1122f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1123f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.orgstatic const uint16_t gRRectIndices[] = {
1124f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // corners
1125f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    0, 1, 5, 0, 5, 4,
1126f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    2, 3, 7, 2, 7, 6,
1127f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    8, 9, 13, 8, 13, 12,
1128f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    10, 11, 15, 10, 15, 14,
11292cf444f7040614b43af67e368f3aa636ebeaa45askia.committer@gmail.com
1130f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // edges
1131f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    1, 2, 6, 1, 6, 5,
1132f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    4, 5, 9, 4, 9, 8,
1133f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    6, 7, 11, 6, 11, 10,
1134f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    9, 10, 14, 9, 14, 13,
11352cf444f7040614b43af67e368f3aa636ebeaa45askia.committer@gmail.com
1136f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // center
1137f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // we place this at the end so that we can ignore these indices when rendering stroke-only
1138f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    5, 6, 10, 5, 10, 9
1139f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org};
1140f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
11415ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIndicesPerStrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
11425ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIndicesPerRRect = SK_ARRAY_COUNT(gRRectIndices);
11435ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kVertsPerRRect = 16;
11445ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kNumRRectsInIndexBuffer = 256;
11455ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt
1146ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonGR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1147ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonGR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1148397536cabe12a9936659870dd220c869789424bacdaltonstatic const GrBuffer* ref_rrect_index_buffer(bool strokeOnly,
1149397536cabe12a9936659870dd220c869789424bacdalton                                              GrResourceProvider* resourceProvider) {
1150ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1151ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1152ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    if (strokeOnly) {
1153eae6200acbec2255ac00ab363ffbe16758ec9076bsalomon        return resourceProvider->findOrCreateInstancedIndexBuffer(
1154ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            gRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1155ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            gStrokeRRectOnlyIndexBufferKey);
1156ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    } else {
1157eae6200acbec2255ac00ab363ffbe16758ec9076bsalomon        return resourceProvider->findOrCreateInstancedIndexBuffer(
1158ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            gRRectIndices, kIndicesPerRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1159ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            gRRectOnlyIndexBufferKey);
1160ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon
1161ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    }
1162ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon}
1163ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon
116476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt///////////////////////////////////////////////////////////////////////////////////////////////////
116576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1166abd30f54b7ff1704a8930c4307ea242d09425d02bsalomonclass RRectCircleRendererBatch : public GrVertexBatch {
116776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
11681b55a963a2374a14bb82eb887bb99ee91680f0ebreed    DEFINE_BATCH_CLASS_ID
11691b55a963a2374a14bb82eb887bb99ee91680f0ebreed
117011bf8b2eae7d1780cb969146422a2ab3b933047absalomon    // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then strokeOnly indicates
117111bf8b2eae7d1780cb969146422a2ab3b933047absalomon    // whether the rrect is only stroked or stroked and filled.
117211bf8b2eae7d1780cb969146422a2ab3b933047absalomon    RRectCircleRendererBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect,
117311bf8b2eae7d1780cb969146422a2ab3b933047absalomon                             float devRadius, float devStrokeWidth, bool strokeOnly)
117411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            : INHERITED(ClassID())
117511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            , fViewMatrixIfUsingLocalCoords(viewMatrix) {
117611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkRect bounds = devRect;
117711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkASSERT(!(devStrokeWidth <= 0 && strokeOnly));
117811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar innerRadius = 0.0f;
117911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar outerRadius = devRadius;
118011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar halfWidth = 0;
118111bf8b2eae7d1780cb969146422a2ab3b933047absalomon        fStroked = false;
118211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        if (devStrokeWidth > 0) {
118311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (SkScalarNearlyZero(devStrokeWidth)) {
118411bf8b2eae7d1780cb969146422a2ab3b933047absalomon                halfWidth = SK_ScalarHalf;
118511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            } else {
118611bf8b2eae7d1780cb969146422a2ab3b933047absalomon                halfWidth = SkScalarHalf(devStrokeWidth);
118711bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
118876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
118911bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (strokeOnly) {
119011bf8b2eae7d1780cb969146422a2ab3b933047absalomon                innerRadius = devRadius - halfWidth;
119111bf8b2eae7d1780cb969146422a2ab3b933047absalomon                fStroked = innerRadius >= 0;
119211bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
119311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            outerRadius += halfWidth;
119411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            bounds.outset(halfWidth, halfWidth);
119511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        }
1196cdaa97bf664e0d584187efc125bfff670a064a9absalomon
119711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // The radii are outset for two reasons. First, it allows the shader to simply perform
119811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
119911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // Second, the outer radius is used to compute the verts of the bounding box that is
120011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // rendered and the outset ensures the box will cover all partially covered by the rrect
120111bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // corners.
120211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        outerRadius += SK_ScalarHalf;
120311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        innerRadius -= SK_ScalarHalf;
120411bf8b2eae7d1780cb969146422a2ab3b933047absalomon
120511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // Expand the rect so all the pixels will be captured.
120611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
120711bf8b2eae7d1780cb969146422a2ab3b933047absalomon
120811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        fGeoData.emplace_back(Geometry { color, innerRadius, outerRadius, bounds });
120911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        this->setBounds(bounds);
121076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
121176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
121236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "RRectCircleBatch"; }
121376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
12149d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary    void computePipelineOptimizations(GrInitInvariantOutput* color,
1215ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrInitInvariantOutput* coverage,
1216ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrBatchToXPOverrides* overrides) const override {
121776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
1218ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        color->setKnownFourComponents(fGeoData[0].fColor);
1219ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        coverage->setUnknownSingleComponent();
122076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
122176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1222e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomonprivate:
1223ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas    void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1224cdaa97bf664e0d584187efc125bfff670a064a9absalomon        // Handle any overrides that affect our GP.
1225ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1226cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!overrides.readsLocalCoords()) {
1227cdaa97bf664e0d584187efc125bfff670a064a9absalomon            fViewMatrixIfUsingLocalCoords.reset();
1228cdaa97bf664e0d584187efc125bfff670a064a9absalomon        }
122976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
123076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1231144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
1232cdaa97bf664e0d584187efc125bfff670a064a9absalomon        // Invert the view matrix as a local matrix (if any other processors require coords).
1233cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkMatrix localMatrix;
1234cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
123576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
123676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
123776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
123876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
1239cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroked, localMatrix));
124076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
124176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
124276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
124376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(vertexStride == sizeof(CircleVertex));
124476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1245b5238a7571c243ba4a154a62575570c3078b3741bsalomon        // drop out the middle quad if we're stroked
1246cdaa97bf664e0d584187efc125bfff670a064a9absalomon        int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPerRRect;
1247397536cabe12a9936659870dd220c869789424bacdalton        SkAutoTUnref<const GrBuffer> indexBuffer(
1248cdaa97bf664e0d584187efc125bfff670a064a9absalomon            ref_rrect_index_buffer(fStroked, target->resourceProvider()));
124976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1250b5238a7571c243ba4a154a62575570c3078b3741bsalomon        InstancedHelper helper;
12517539856c1b9cbb1886a6a498cc534b77fc83ddb2bsalomon        CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target,
1252b5238a7571c243ba4a154a62575570c3078b3741bsalomon            kTriangles_GrPrimitiveType, vertexStride, indexBuffer, kVertsPerRRect,
1253b5238a7571c243ba4a154a62575570c3078b3741bsalomon            indicesPerInstance, instanceCount));
1254b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts || !indexBuffer) {
12554b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            SkDebugf("Could not allocate vertices\n");
12564b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
12574b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
12584b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
125976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
1260144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& args = fGeoData[i];
126176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1262bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = args.fColor;
126376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar outerRadius = args.fOuterRadius;
126476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1265bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel            const SkRect& bounds = args.fDevBounds;
126676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
126776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yCoords[4] = {
126876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fTop,
126976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fTop + outerRadius,
127076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fBottom - outerRadius,
127176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fBottom
127276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            };
127376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
127476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
127576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // The inner radius in the vertex data must be specified in normalized space.
127676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar innerRadius = args.fInnerRadius / args.fOuterRadius;
127776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            for (int i = 0; i < 4; ++i) {
127876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1279bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
128076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
128176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
128276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
128376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
128476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
128576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
1286bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
128776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
128876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
128976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
129076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
129176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
129276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
1293bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
129476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
129576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
129676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
129776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
129876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
129976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1300bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
130176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
130276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
130376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
130476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
130576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            }
130676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
130776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1308342bfc25de5b0452b1551bf9db4bf45eac7718b2bsalomon        helper.recordDraw(target, gp);
130976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
131076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1311cb02b38b2c48bfde333ce3c699dd0451e2d867fabsalomon    bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
1312abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>();
1313abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1314abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
13158cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
13168cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
13178cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
1318cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (fStroked != that->fStroked) {
131976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
132076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
132176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1322cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
132376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
132476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
132576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1326cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
132799c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
132876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
132976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
133076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
133111bf8b2eae7d1780cb969146422a2ab3b933047absalomon    struct Geometry {
133211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        GrColor  fColor;
133311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fInnerRadius;
133411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fOuterRadius;
133511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkRect fDevBounds;
133611bf8b2eae7d1780cb969146422a2ab3b933047absalomon    };
133711bf8b2eae7d1780cb969146422a2ab3b933047absalomon
1338cdaa97bf664e0d584187efc125bfff670a064a9absalomon    bool                         fStroked;
1339cdaa97bf664e0d584187efc125bfff670a064a9absalomon    SkMatrix                     fViewMatrixIfUsingLocalCoords;
134076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
13411b55a963a2374a14bb82eb887bb99ee91680f0ebreed
13421b55a963a2374a14bb82eb887bb99ee91680f0ebreed    typedef GrVertexBatch INHERITED;
134376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
134476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1345abd30f54b7ff1704a8930c4307ea242d09425d02bsalomonclass RRectEllipseRendererBatch : public GrVertexBatch {
134676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
13471b55a963a2374a14bb82eb887bb99ee91680f0ebreed    DEFINE_BATCH_CLASS_ID
13481b55a963a2374a14bb82eb887bb99ee91680f0ebreed
134911bf8b2eae7d1780cb969146422a2ab3b933047absalomon    // If devStrokeWidths values are <= 0 indicates then fill only. Otherwise, strokeOnly indicates
135011bf8b2eae7d1780cb969146422a2ab3b933047absalomon    // whether the rrect is only stroked or stroked and filled.
135111bf8b2eae7d1780cb969146422a2ab3b933047absalomon    static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect,
135211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                               float devXRadius, float devYRadius, SkVector devStrokeWidths,
135311bf8b2eae7d1780cb969146422a2ab3b933047absalomon                               bool strokeOnly) {
135411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkASSERT(devXRadius > 0.5);
135511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkASSERT(devYRadius > 0.5);
135611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkASSERT((devStrokeWidths.fX > 0) == (devStrokeWidths.fY > 0));
135711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkASSERT(!(strokeOnly && devStrokeWidths.fX <= 0));
135811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar innerXRadius = 0.0f;
135911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar innerYRadius = 0.0f;
136011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkRect bounds = devRect;
136111bf8b2eae7d1780cb969146422a2ab3b933047absalomon        bool stroked = false;
136211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        if (devStrokeWidths.fX > 0) {
136311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (SkScalarNearlyZero(devStrokeWidths.length())) {
136411bf8b2eae7d1780cb969146422a2ab3b933047absalomon                devStrokeWidths.set(SK_ScalarHalf, SK_ScalarHalf);
136511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            } else {
136611bf8b2eae7d1780cb969146422a2ab3b933047absalomon                devStrokeWidths.scale(SK_ScalarHalf);
136711bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
136811bf8b2eae7d1780cb969146422a2ab3b933047absalomon
136911bf8b2eae7d1780cb969146422a2ab3b933047absalomon            // we only handle thick strokes for near-circular ellipses
137011bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (devStrokeWidths.length() > SK_ScalarHalf &&
137111bf8b2eae7d1780cb969146422a2ab3b933047absalomon                (SK_ScalarHalf*devXRadius > devYRadius || SK_ScalarHalf*devYRadius > devXRadius)) {
137211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                return nullptr;
137311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
137411bf8b2eae7d1780cb969146422a2ab3b933047absalomon
137511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
137611bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (devStrokeWidths.fX*(devYRadius*devYRadius) <
137711bf8b2eae7d1780cb969146422a2ab3b933047absalomon                (devStrokeWidths.fY*devStrokeWidths.fY)*devXRadius) {
137811bf8b2eae7d1780cb969146422a2ab3b933047absalomon                return nullptr;
137911bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
138011bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (devStrokeWidths.fY*(devXRadius*devXRadius) <
138111bf8b2eae7d1780cb969146422a2ab3b933047absalomon                (devStrokeWidths.fX*devStrokeWidths.fX)*devYRadius) {
138211bf8b2eae7d1780cb969146422a2ab3b933047absalomon                return nullptr;
138311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
13847f06c6947a3bef78dc57b9252779567c33604c90bsalomon
138511bf8b2eae7d1780cb969146422a2ab3b933047absalomon            // this is legit only if scale & translation (which should be the case at the moment)
138611bf8b2eae7d1780cb969146422a2ab3b933047absalomon            if (strokeOnly) {
138711bf8b2eae7d1780cb969146422a2ab3b933047absalomon                innerXRadius = devXRadius - devStrokeWidths.fX;
138811bf8b2eae7d1780cb969146422a2ab3b933047absalomon                innerYRadius = devYRadius - devStrokeWidths.fY;
138911bf8b2eae7d1780cb969146422a2ab3b933047absalomon                stroked = (innerXRadius >= 0 && innerYRadius >= 0);
139011bf8b2eae7d1780cb969146422a2ab3b933047absalomon            }
139111bf8b2eae7d1780cb969146422a2ab3b933047absalomon
139211bf8b2eae7d1780cb969146422a2ab3b933047absalomon            devXRadius += devStrokeWidths.fX;
139311bf8b2eae7d1780cb969146422a2ab3b933047absalomon            devYRadius += devStrokeWidths.fY;
139411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            bounds.outset(devStrokeWidths.fX, devStrokeWidths.fY);
139511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        }
139611bf8b2eae7d1780cb969146422a2ab3b933047absalomon
139711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        // Expand the rect so all the pixels will be captured.
139811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
139911bf8b2eae7d1780cb969146422a2ab3b933047absalomon
140011bf8b2eae7d1780cb969146422a2ab3b933047absalomon        RRectEllipseRendererBatch* batch = new RRectEllipseRendererBatch();
140111bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->fStroked = stroked;
140211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->fViewMatrixIfUsingLocalCoords = viewMatrix;
140311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->fGeoData.emplace_back(
140411bf8b2eae7d1780cb969146422a2ab3b933047absalomon            Geometry {color, devXRadius, devYRadius, innerXRadius, innerYRadius, bounds});
140511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        batch->setBounds(bounds);
140611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        return batch;
140776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
140876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
140936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "RRectEllipseRendererBatch"; }
141076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
14119d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary    void computePipelineOptimizations(GrInitInvariantOutput* color,
1412ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrInitInvariantOutput* coverage,
1413ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas                                      GrBatchToXPOverrides* overrides) const override {
141476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
1415ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        color->setKnownFourComponents(fGeoData[0].fColor);
1416ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        coverage->setUnknownSingleComponent();
141776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
141876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1419e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomonprivate:
142011bf8b2eae7d1780cb969146422a2ab3b933047absalomon    RRectEllipseRendererBatch() : INHERITED(ClassID()) {}
142111bf8b2eae7d1780cb969146422a2ab3b933047absalomon
1422ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas    void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1423cdaa97bf664e0d584187efc125bfff670a064a9absalomon        // Handle overrides that affect our GP.
1424ff2103200bad7abcf8929ae22ac78a9f4f725142ethannicholas        overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1425cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!overrides.readsLocalCoords()) {
1426cdaa97bf664e0d584187efc125bfff670a064a9absalomon            fViewMatrixIfUsingLocalCoords.reset();
1427cdaa97bf664e0d584187efc125bfff670a064a9absalomon        }
142876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
142976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1430144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
1431cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkMatrix localMatrix;
1432cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
143376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
143476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
143576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
143676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
1437cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkAutoTUnref<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
143876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
143976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
144076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
144176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(vertexStride == sizeof(EllipseVertex));
144276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1443b5238a7571c243ba4a154a62575570c3078b3741bsalomon        // drop out the middle quad if we're stroked
1444cdaa97bf664e0d584187efc125bfff670a064a9absalomon        int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPerRRect;
1445397536cabe12a9936659870dd220c869789424bacdalton        SkAutoTUnref<const GrBuffer> indexBuffer(
1446cdaa97bf664e0d584187efc125bfff670a064a9absalomon            ref_rrect_index_buffer(fStroked, target->resourceProvider()));
144776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1448b5238a7571c243ba4a154a62575570c3078b3741bsalomon        InstancedHelper helper;
1449b5238a7571c243ba4a154a62575570c3078b3741bsalomon        EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
14507539856c1b9cbb1886a6a498cc534b77fc83ddb2bsalomon            helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer,
1451b5238a7571c243ba4a154a62575570c3078b3741bsalomon            kVertsPerRRect, indicesPerInstance, instanceCount));
1452b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts || !indexBuffer) {
14534b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            SkDebugf("Could not allocate vertices\n");
14544b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
14554b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
14564b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
145776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
1458144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& args = fGeoData[i];
145976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1460bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = args.fColor;
1461bb2ff94e223014403f775c3532a25cc25b00c949brianosman
146276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // Compute the reciprocals of the radii here to save time in the shader
146376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
146476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yRadRecip = SkScalarInvert(args.fYRadius);
146576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
146676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
146776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
146876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // Extend the radii out half a pixel to antialias.
146976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xOuterRadius = args.fXRadius + SK_ScalarHalf;
147076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yOuterRadius = args.fYRadius + SK_ScalarHalf;
147176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1472bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel            const SkRect& bounds = args.fDevBounds;
147376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
147476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yCoords[4] = {
147576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fTop,
147676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fTop + yOuterRadius,
147776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fBottom - yOuterRadius,
147876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fBottom
147976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            };
148076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yOuterOffsets[4] = {
148176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                yOuterRadius,
148276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                SK_ScalarNearlyZero, // we're using inversesqrt() in shader, so can't be exactly 0
148376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                SK_ScalarNearlyZero,
148476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                yOuterRadius
148576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            };
148676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
148776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            for (int i = 0; i < 4; ++i) {
148876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1489bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
149076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
149176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
149276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
149376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
149476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
149576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
1496bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
149776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
149876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
149976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
150076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
150176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
150276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
1503bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
150476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
150576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
150676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
150776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
150876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
150976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1510bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
151176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
151276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
151376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
151476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
151576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            }
151676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
1517342bfc25de5b0452b1551bf9db4bf45eac7718b2bsalomon        helper.recordDraw(target, gp);
151876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
151976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1520cb02b38b2c48bfde333ce3c699dd0451e2d867fabsalomon    bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
1521abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        RRectEllipseRendererBatch* that = t->cast<RRectEllipseRendererBatch>();
1522abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon
1523abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1524abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
15258cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
15268cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
15278cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
1528cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (fStroked != that->fStroked) {
152976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
153076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
153176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1532cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
153376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
153476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
153576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1536cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
153799c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
153876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
153976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
154076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
154111bf8b2eae7d1780cb969146422a2ab3b933047absalomon    struct Geometry {
154211bf8b2eae7d1780cb969146422a2ab3b933047absalomon        GrColor fColor;
154311bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fXRadius;
154411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fYRadius;
154511bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fInnerXRadius;
154611bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkScalar fInnerYRadius;
154711bf8b2eae7d1780cb969146422a2ab3b933047absalomon        SkRect fDevBounds;
154811bf8b2eae7d1780cb969146422a2ab3b933047absalomon    };
154911bf8b2eae7d1780cb969146422a2ab3b933047absalomon
1550cdaa97bf664e0d584187efc125bfff670a064a9absalomon    bool                            fStroked;
1551cdaa97bf664e0d584187efc125bfff670a064a9absalomon    SkMatrix                        fViewMatrixIfUsingLocalCoords;
1552cdaa97bf664e0d584187efc125bfff670a064a9absalomon    SkSTArray<1, Geometry, true>    fGeoData;
15531b55a963a2374a14bb82eb887bb99ee91680f0ebreed
15541b55a963a2374a14bb82eb887bb99ee91680f0ebreed    typedef GrVertexBatch INHERITED;
155576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
155676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1557abd30f54b7ff1704a8930c4307ea242d09425d02bsalomonstatic GrDrawBatch* create_rrect_batch(GrColor color,
1558abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                       const SkMatrix& viewMatrix,
1559abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                       const SkRRect& rrect,
1560abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                       const SkStrokeRec& stroke) {
15613e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkASSERT(viewMatrix.rectStaysRect());
15623e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkASSERT(rrect.isSimple());
15633e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkASSERT(!rrect.isOval());
15643e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
15653e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    // RRect batchs only handle simple, but not too simple, rrects
1566f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // do any matrix crunching before we reset the draw state for device coords
1567f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    const SkRect& rrectBounds = rrect.getBounds();
1568d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    SkRect bounds;
1569d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    viewMatrix.mapRect(&bounds, rrectBounds);
1570f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1571f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkVector radii = rrect.getSimpleRadii();
15728059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX +
15738059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                   viewMatrix[SkMatrix::kMSkewY]*radii.fY);
15748059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX +
15758059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                   viewMatrix[SkMatrix::kMScaleY]*radii.fY);
15766bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
1577f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkStrokeRec::Style style = stroke.getStyle();
1578f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
157911bf8b2eae7d1780cb969146422a2ab3b933047absalomon    // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill-only draws.
158011bf8b2eae7d1780cb969146422a2ab3b933047absalomon    SkVector scaledStroke = {-1, -1};
1581f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkScalar strokeWidth = stroke.getWidth();
1582f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
15830a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
15840a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org                        SkStrokeRec::kHairline_Style == style;
15850a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
15860a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
15870a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if (hasStroke) {
15880a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        if (SkStrokeRec::kHairline_Style == style) {
15890a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org            scaledStroke.set(1, 1);
15900a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        } else {
15918059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
15928059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                                       viewMatrix[SkMatrix::kMSkewY]));
15938059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
15948059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                                       viewMatrix[SkMatrix::kMScaleY]));
15950a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        }
15960a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
15970a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        // if half of strokewidth is greater than radius, we don't handle that right now
15980a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) {
159996fcdcc219d2a0d3579719b84b28bede76efba64halcanary            return nullptr;
16000a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        }
16010a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    }
16020a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
16030a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
16040a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
16050a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // patch will have fractional coverage. This only matters when the interior is actually filled.
16060a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // We could consider falling back to rect rendering here, since a tiny radius is
16070a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // indistinguishable from a square corner.
16080a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
160996fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
1610f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    }
1611f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1612f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // if the corners are circles, use the circle renderer
16130a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
161411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX,
161511bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                            isStrokeOnly);
16166bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org    // otherwise we use the ellipse renderer
1617f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    } else {
161811bf8b2eae7d1780cb969146422a2ab3b933047absalomon        return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRadius, yRadius,
161911bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                                 scaledStroke, isStrokeOnly);
1620f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1621f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    }
16223e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
16233e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
1624b56f92783a5d84347b65f4f01ec3668096649d13robertphillipsGrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color,
16250cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips                                              const SkMatrix& viewMatrix,
16260cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips                                              const SkRRect& rrect,
16270cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips                                              const SkStrokeRec& stroke,
16280cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips                                              GrShaderCaps* shaderCaps) {
16290cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips    if (rrect.isOval()) {
1630b56f92783a5d84347b65f4f01ec3668096649d13robertphillips        return CreateOvalBatch(color, viewMatrix, rrect.getBounds(), stroke, shaderCaps);
16313e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
16323e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
16330cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips    if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
16340cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips        return nullptr;
16353e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
16363e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
16370cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips    return create_rrect_batch(color, viewMatrix, rrect, stroke);
1638f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org}
16393e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
164011bf8b2eae7d1780cb969146422a2ab3b933047absalomon///////////////////////////////////////////////////////////////////////////////
164111bf8b2eae7d1780cb969146422a2ab3b933047absalomon
164211bf8b2eae7d1780cb969146422a2ab3b933047absalomonGrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color,
164311bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                             const SkMatrix& viewMatrix,
164411bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                             const SkRect& oval,
164511bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                             const SkStrokeRec& stroke,
164611bf8b2eae7d1780cb969146422a2ab3b933047absalomon                                             GrShaderCaps* shaderCaps) {
164711bf8b2eae7d1780cb969146422a2ab3b933047absalomon    // we can draw circles
164811bf8b2eae7d1780cb969146422a2ab3b933047absalomon    if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(viewMatrix)) {
164911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        return new CircleBatch(color, viewMatrix, oval, stroke);
165011bf8b2eae7d1780cb969146422a2ab3b933047absalomon    }
165111bf8b2eae7d1780cb969146422a2ab3b933047absalomon
165211bf8b2eae7d1780cb969146422a2ab3b933047absalomon    // if we have shader derivative support, render as device-independent
165311bf8b2eae7d1780cb969146422a2ab3b933047absalomon    if (shaderCaps->shaderDerivativeSupport()) {
165411bf8b2eae7d1780cb969146422a2ab3b933047absalomon        return DIEllipseBatch::Create(color, viewMatrix, oval, stroke);
165511bf8b2eae7d1780cb969146422a2ab3b933047absalomon    }
165611bf8b2eae7d1780cb969146422a2ab3b933047absalomon
165711bf8b2eae7d1780cb969146422a2ab3b933047absalomon    // otherwise axis-aligned ellipses only
165811bf8b2eae7d1780cb969146422a2ab3b933047absalomon    if (viewMatrix.rectStaysRect()) {
165911bf8b2eae7d1780cb969146422a2ab3b933047absalomon        return EllipseBatch::Create(color, viewMatrix, oval, stroke);
166011bf8b2eae7d1780cb969146422a2ab3b933047absalomon    }
166111bf8b2eae7d1780cb969146422a2ab3b933047absalomon
166211bf8b2eae7d1780cb969146422a2ab3b933047absalomon    return nullptr;
166311bf8b2eae7d1780cb969146422a2ab3b933047absalomon}
166411bf8b2eae7d1780cb969146422a2ab3b933047absalomon
166511bf8b2eae7d1780cb969146422a2ab3b933047absalomon///////////////////////////////////////////////////////////////////////////////
16663e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
16673e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt#ifdef GR_TEST_UTILS
16683e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
1669abd30f54b7ff1704a8930c4307ea242d09425d02bsalomonDRAW_BATCH_TEST_DEFINE(CircleBatch) {
16703e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrix(random);
16713e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
16726c891107ce0a8431f2327cb8b2f1bfd363cabbbejoshualitt    SkRect circle = GrTest::TestSquare(random);
167311bf8b2eae7d1780cb969146422a2ab3b933047absalomon    return new CircleBatch(color, viewMatrix, circle, GrTest::TestStrokeRec(random));
16743e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
16753e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
1676abd30f54b7ff1704a8930c4307ea242d09425d02bsalomonDRAW_BATCH_TEST_DEFINE(EllipseBatch) {
16773e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
16783e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
16796c891107ce0a8431f2327cb8b2f1bfd363cabbbejoshualitt    SkRect ellipse = GrTest::TestSquare(random);
168011bf8b2eae7d1780cb969146422a2ab3b933047absalomon    return EllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
16813e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
16823e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
1683abd30f54b7ff1704a8930c4307ea242d09425d02bsalomonDRAW_BATCH_TEST_DEFINE(DIEllipseBatch) {
16843e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrix(random);
16853e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
16866c891107ce0a8431f2327cb8b2f1bfd363cabbbejoshualitt    SkRect ellipse = GrTest::TestSquare(random);
168711bf8b2eae7d1780cb969146422a2ab3b933047absalomon    return DIEllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
16883e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
16893e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
1690abd30f54b7ff1704a8930c4307ea242d09425d02bsalomonDRAW_BATCH_TEST_DEFINE(RRectBatch) {
16913e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
16923e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
16933e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    const SkRRect& rrect = GrTest::TestRRectSimple(random);
169421279c7ada1e47e8bfc6375f67768c8eedffb680joshualitt    return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(random));
16953e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
16963e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
16973e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt#endif
1698