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
1076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt#include "GrBatch.h"
1176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt#include "GrBatchTarget.h"
123e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt#include "GrBatchTest.h"
1381312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org#include "GrDrawTarget.h"
14eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "GrGeometryProcessor.h"
15605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdaniel#include "GrInvariantOutput.h"
168dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel#include "GrPipelineBuilder.h"
1776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt#include "GrProcessor.h"
18ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon#include "GrResourceProvider.h"
1972e3ae486c66871c2043eac4f08d85d419fbca2absalomon#include "GrVertexBuffer.h"
20f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org#include "SkRRect.h"
2181312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org#include "SkStrokeRec.h"
220a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org#include "SkTLazy.h"
230a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org#include "effects/GrRRectEffect.h"
24eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "gl/GrGLProcessor.h"
25eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "gl/GrGLSL.h"
26eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "gl/GrGLGeometryProcessor.h"
27eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "gl/builders/GrGLProgramBuilder.h"
28234d4fba75aac009e34c088037fcd9e244798c40commit-bot@chromium.org
2976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt// TODO(joshualitt) - Break this file up during GrBatch post implementation cleanup
3076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
3181312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orgnamespace {
325ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// TODO(joshualitt) add per vertex colors
3381312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orgstruct CircleVertex {
34972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fPos;
35972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fOffset;
3681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    SkScalar fOuterRadius;
3781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    SkScalar fInnerRadius;
3881312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org};
3981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
4081312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orgstruct EllipseVertex {
41972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fPos;
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;
49972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fOuterOffset;
50972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fInnerOffset;
515242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org};
525242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5381312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orginline bool circle_stays_circle(const SkMatrix& m) {
5481312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    return m.isSimilarity();
5581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org}
5681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
5781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org}
5881312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
5990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
6090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
6190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/**
62ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon * The output of this effect is a modulation of the input color and coverage for a circle. It
63ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon * operates in a space normalized by the circle radius (outer radius in the case of a stroke)
64ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon * with origin at the circle center. Two   vertex attributes are used:
65ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *    vec2f : position in device space of the bounding geometry vertices
66ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *    vec4f : (p.xy, outerRad, innerRad)
67ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *             p is the position in the normalized space.
68ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *             outerRad is the outerRadius in device space.
69ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *             innerRad is the innerRadius in normalized space (ignored if not stroking).
7090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */
7190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
72249af15fb82833d2274850c589812b6e69df0033joshualittclass CircleEdgeEffect : public GrGeometryProcessor {
7390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic:
74d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt    static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix) {
75d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt        return SkNEW_ARGS(CircleEdgeEffect, (color, stroke, localMatrix));
7690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
7790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
7871c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inPosition() const { return fInPosition; }
7971c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inCircleEdge() const { return fInCircleEdge; }
8088c23fc6e8ed0243159fd17d815b4f813805647bjoshualitt    GrColor color() const { return fColor; }
81e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    const SkMatrix& localMatrix() const { return fLocalMatrix; }
8290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    virtual ~CircleEdgeEffect() {}
8390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
8436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "CircleEdge"; }
8590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
8690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    inline bool isStroked() const { return fStroke; }
8790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
88b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    class GLProcessor : public GrGLGeometryProcessor {
8990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    public:
90eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        GLProcessor(const GrGeometryProcessor&,
919b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                    const GrBatchTracker&)
929b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            : fColor(GrColor_ILLEGAL) {}
9390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
9436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
952dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            const CircleEdgeEffect& ce = args.fGP.cast<CircleEdgeEffect>();
969b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            GrGLGPBuilder* pb = args.fPB;
979b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            const BatchTracker& local = args.fBT.cast<BatchTracker>();
982dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
992dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
100abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit attributes
101abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            vsBuilder->emitAttributes(ce);
102abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
10374077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            GrGLVertToFrag v(kVec4f_GrSLType);
10474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            args.fPB->addVarying("CircleEdge", &v);
1052dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            vsBuilder->codeAppendf("%s = %s;", v.vsOut(), ce.inCircleEdge()->fName);
10690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
1079b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            // Setup pass through color
1089b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
1099b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                                        &fColorUniform);
1109b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
111abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // Setup position
112e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt            this->setupPosition(pb, gpArgs, ce.inPosition()->fName);
113abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
114abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit transforms
11546d36f0e7b709a077c647841eee23bd3efdc4117robertphillips            this->emitTransforms(args.fPB, gpArgs->fPositionVar, ce.inPosition()->fName,
116567ff2f6143ecb993dbedede402a43feb71c420atfarina                                 ce.localMatrix(), args.fTransformsIn, args.fTransformsOut);
1174973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
11829bee0fe657fabf7c396502b69c9167fba13eaaaegdaniel            GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
11974077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn());
120ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon            fsBuilder->codeAppendf("float edgeAlpha = clamp(%s.z * (1.0 - d), 0.0, 1.0);", v.fsIn());
1212dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            if (ce.isStroked()) {
122ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon                fsBuilder->codeAppendf("float innerAlpha = clamp(%s.z * (d - %s.w), 0.0, 1.0);",
123ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon                                       v.fsIn(), v.fsIn());
12474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("edgeAlpha *= innerAlpha;");
12590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            }
1260a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org
1272dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
12890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
12990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
13046d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        static void GenKey(const GrGeometryProcessor& gp,
1319b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                           const GrBatchTracker& bt,
132cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                           const GrGLSLCaps&,
133b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                           GrProcessorKeyBuilder* b) {
1349b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            const BatchTracker& local = bt.cast<BatchTracker>();
135e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt            const CircleEdgeEffect& ce = gp.cast<CircleEdgeEffect>();
136e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt            uint16_t key = ce.isStroked() ? 0x1 : 0x0;
137e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt            key |= local.fUsesLocalCoords && ce.localMatrix().hasPerspective() ? 0x2 : 0x0;
1388fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt            b->add32(key << 16 | local.fInputColorType);
13990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
14090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
1419b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        virtual void setData(const GrGLProgramDataManager& pdman,
1429b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                             const GrPrimitiveProcessor& gp,
14336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                             const GrBatchTracker& bt) override {
1449b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            const BatchTracker& local = bt.cast<BatchTracker>();
1459b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
1469b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                GrGLfloat c[4];
1479b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                GrColorToRGBAFloat(local.fColor, c);
1489b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                pdman.set4fv(fColorUniform, 1, c);
1499b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                fColor = local.fColor;
1509b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            }
1519b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        }
15290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
153e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        void setTransformData(const GrPrimitiveProcessor& primProc,
154e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              const GrGLProgramDataManager& pdman,
155e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              int index,
156e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
157e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt            this->setTransformDataHelper<CircleEdgeEffect>(primProc, pdman, index, transforms);
158e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        }
159e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt
16090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    private:
1619b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrColor fColor;
1629b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        UniformHandle fColorUniform;
163249af15fb82833d2274850c589812b6e69df0033joshualitt        typedef GrGLGeometryProcessor INHERITED;
16490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    };
16590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
166eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    virtual void getGLProcessorKey(const GrBatchTracker& bt,
167cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                   const GrGLSLCaps& caps,
16836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                                   GrProcessorKeyBuilder* b) const override {
169eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        GLProcessor::GenKey(*this, bt, caps, b);
170eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
171eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
172abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt    virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
173cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                                     const GrGLSLCaps&) const override {
174eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        return SkNEW_ARGS(GLProcessor, (*this, bt));
175eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
17690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
17736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const override {
1789b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        BatchTracker* local = bt->cast<BatchTracker>();
1799b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
180290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt        local->fUsesLocalCoords = init.fUsesLocalCoords;
1819b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    }
1829b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
18390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgprivate:
184d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt    CircleEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix)
185e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        : fColor(color)
186e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        , fLocalMatrix(localMatrix) {
187eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        this->initClassID<CircleEdgeEffect>();
188c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
189c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco                                                       kHigh_GrSLPrecision));
19071c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt        fInCircleEdge = &this->addVertexAttrib(Attribute("inCircleEdge",
1912dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt                                                           kVec4f_GrVertexAttribType));
19290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        fStroke = stroke;
19390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
19490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
1959b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    struct BatchTracker {
1969b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrGPInput fInputColorType;
1979b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrColor fColor;
198290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt        bool fUsesLocalCoords;
1999b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    };
2009b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
20188c23fc6e8ed0243159fd17d815b4f813805647bjoshualitt    GrColor fColor;
202e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    SkMatrix fLocalMatrix;
20371c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInPosition;
20471c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInCircleEdge;
20590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    bool fStroke;
20690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
207b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
20890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
209249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGeometryProcessor INHERITED;
21090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org};
21190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
212b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleEdgeEffect);
21390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
214b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrGeometryProcessor* CircleEdgeEffect::TestCreate(SkRandom* random,
215b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                  GrContext* context,
216b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                  const GrDrawTargetCaps&,
217b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                  GrTexture* textures[]) {
2188059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    return CircleEdgeEffect::Create(GrRandomColor(random),
2198059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                    random->nextBool(),
2204eaf9cef5a76098f78efac30beb966ac833d32c2joshualitt                                    GrTest::TestMatrix(random));
22190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}
22290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
22390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
22490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
22590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/**
22690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * The output of this effect is a modulation of the input color and coverage for an axis-aligned
2278be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii,
2288be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com * in both x and y directions.
2298be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com *
2306bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
23190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */
23290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
233249af15fb82833d2274850c589812b6e69df0033joshualittclass EllipseEdgeEffect : public GrGeometryProcessor {
23490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic:
235d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt    static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix) {
236d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt        return SkNEW_ARGS(EllipseEdgeEffect, (color, stroke, localMatrix));
23790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
23890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
23990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    virtual ~EllipseEdgeEffect() {}
24090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
24136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "EllipseEdge"; }
2422dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
24371c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inPosition() const { return fInPosition; }
24471c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inEllipseOffset() const { return fInEllipseOffset; }
24571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inEllipseRadii() const { return fInEllipseRadii; }
24688c23fc6e8ed0243159fd17d815b4f813805647bjoshualitt    GrColor color() const { return fColor; }
247e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    const SkMatrix& localMatrix() const { return fLocalMatrix; }
248249af15fb82833d2274850c589812b6e69df0033joshualitt
24990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    inline bool isStroked() const { return fStroke; }
25090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
251b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    class GLProcessor : public GrGLGeometryProcessor {
25290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    public:
253eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        GLProcessor(const GrGeometryProcessor&,
2549b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                    const GrBatchTracker&)
2559b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            : fColor(GrColor_ILLEGAL) {}
25690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
25736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
2582dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            const EllipseEdgeEffect& ee = args.fGP.cast<EllipseEdgeEffect>();
2599b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            GrGLGPBuilder* pb = args.fPB;
2609b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            const BatchTracker& local = args.fBT.cast<BatchTracker>();
2612dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
26290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
263abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit attributes
264abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            vsBuilder->emitAttributes(ee);
265abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
26674077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            GrGLVertToFrag ellipseOffsets(kVec2f_GrSLType);
26774077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            args.fPB->addVarying("EllipseOffsets", &ellipseOffsets);
26874077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            vsBuilder->codeAppendf("%s = %s;", ellipseOffsets.vsOut(),
2692dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt                                   ee.inEllipseOffset()->fName);
27090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
27174077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            GrGLVertToFrag ellipseRadii(kVec4f_GrSLType);
27274077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            args.fPB->addVarying("EllipseRadii", &ellipseRadii);
27374077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            vsBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(),
2742dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt                                   ee.inEllipseRadii()->fName);
2752dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
2769b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            // Setup pass through color
2779b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
2789b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                                        &fColorUniform);
2799b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
280abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // Setup position
281e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt            this->setupPosition(pb, gpArgs, ee.inPosition()->fName);
282abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
283abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit transforms
28446d36f0e7b709a077c647841eee23bd3efdc4117robertphillips            this->emitTransforms(args.fPB, gpArgs->fPositionVar, ee.inPosition()->fName,
285abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt                                 ee.localMatrix(), args.fTransformsIn, args.fTransformsOut);
2864973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
2878be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com            // for outer curve
28829bee0fe657fabf7c396502b69c9167fba13eaaaegdaniel            GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
28974077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppendf("vec2 scaledOffset = %s*%s.xy;", ellipseOffsets.fsIn(),
29074077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                                   ellipseRadii.fsIn());
29174077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
29274077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppendf("vec2 grad = 2.0*scaledOffset*%s.xy;", ellipseRadii.fsIn());
29374077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppend("float grad_dot = dot(grad, grad);");
29474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt
2951b035d82d2b8b50ae334463edd06e4c5e0639311commit-bot@chromium.org            // avoid calling inversesqrt on zero.
29674077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
29774077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
29874077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
299f58d8540a42e5138e7cdb1dd1e0b4de0fa3c4a10jvanverth@google.com
3006bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            // for inner curve
3012dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            if (ee.isStroked()) {
30274077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppendf("scaledOffset = %s*%s.zw;",
30374077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                                       ellipseOffsets.fsIn(), ellipseRadii.fsIn());
30474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
30574077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;",
30674077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                                       ellipseRadii.fsIn());
30774077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
30874077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
30990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            }
31090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
3112dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
31290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
31390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
31446d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        static void GenKey(const GrGeometryProcessor& gp,
3159b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                           const GrBatchTracker& bt,
316cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                           const GrGLSLCaps&,
317b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                           GrProcessorKeyBuilder* b) {
3189b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            const BatchTracker& local = bt.cast<BatchTracker>();
319e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt            const EllipseEdgeEffect& ee = gp.cast<EllipseEdgeEffect>();
320e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt            uint16_t key = ee.isStroked() ? 0x1 : 0x0;
321e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt            key |= local.fUsesLocalCoords && ee.localMatrix().hasPerspective() ? 0x2 : 0x0;
3228fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt            b->add32(key << 16 | local.fInputColorType);
32390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
32490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
3259b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        virtual void setData(const GrGLProgramDataManager& pdman,
3269b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                             const GrPrimitiveProcessor& gp,
32736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                             const GrBatchTracker& bt) override {
328ee2af95db72152dfa61c841875df0594ca93437djoshualitt
3299b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            const BatchTracker& local = bt.cast<BatchTracker>();
3309b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
3319b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                GrGLfloat c[4];
3329b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                GrColorToRGBAFloat(local.fColor, c);
3339b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                pdman.set4fv(fColorUniform, 1, c);
3349b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                fColor = local.fColor;
3359b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            }
33690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
33790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
338e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        void setTransformData(const GrPrimitiveProcessor& primProc,
339e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              const GrGLProgramDataManager& pdman,
340e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              int index,
341e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
342e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt            this->setTransformDataHelper<EllipseEdgeEffect>(primProc, pdman, index, transforms);
343e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        }
344e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt
34590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    private:
3469b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrColor fColor;
3479b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        UniformHandle fColorUniform;
3489b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
349249af15fb82833d2274850c589812b6e69df0033joshualitt        typedef GrGLGeometryProcessor INHERITED;
35090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    };
35190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
352eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    virtual void getGLProcessorKey(const GrBatchTracker& bt,
353cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                   const GrGLSLCaps& caps,
35436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                                   GrProcessorKeyBuilder* b) const override {
355eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        GLProcessor::GenKey(*this, bt, caps, b);
356eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
357eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
358abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt    virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
359cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                                     const GrGLSLCaps&) const override {
360eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        return SkNEW_ARGS(GLProcessor, (*this, bt));
361eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
362eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
36336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const override {
3649b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        BatchTracker* local = bt->cast<BatchTracker>();
3659b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
366290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt        local->fUsesLocalCoords = init.fUsesLocalCoords;
3679b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    }
3689b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
36990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgprivate:
370d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt    EllipseEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix)
371e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        : fColor(color)
372e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        , fLocalMatrix(localMatrix) {
373eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        this->initClassID<EllipseEdgeEffect>();
37471c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
37571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt        fInEllipseOffset = &this->addVertexAttrib(Attribute("inEllipseOffset",
3762dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt                                                              kVec2f_GrVertexAttribType));
37771c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt        fInEllipseRadii = &this->addVertexAttrib(Attribute("inEllipseRadii",
3782dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt                                                             kVec4f_GrVertexAttribType));
37990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        fStroke = stroke;
38090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
38190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
3829b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    struct BatchTracker {
3839b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrGPInput fInputColorType;
3849b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrColor fColor;
385290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt        bool fUsesLocalCoords;
3869b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    };
3879b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
38871c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInPosition;
38971c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseOffset;
39071c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseRadii;
39188c23fc6e8ed0243159fd17d815b4f813805647bjoshualitt    GrColor fColor;
392e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    SkMatrix fLocalMatrix;
39390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    bool fStroke;
39490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
395b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
39690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
397249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGeometryProcessor INHERITED;
39890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org};
39990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
400b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseEdgeEffect);
40190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
402b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrGeometryProcessor* EllipseEdgeEffect::TestCreate(SkRandom* random,
403b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                   GrContext* context,
404b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                   const GrDrawTargetCaps&,
405b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                   GrTexture* textures[]) {
4068059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    return EllipseEdgeEffect::Create(GrRandomColor(random),
4078059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                     random->nextBool(),
4084eaf9cef5a76098f78efac30beb966ac833d32c2joshualitt                                     GrTest::TestMatrix(random));
40990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}
41090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
41190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
41290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
4135242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org/**
4146fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.com * The output of this effect is a modulation of the input color and coverage for an ellipse,
4155242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * specified as a 2D offset from center for both the outer and inner paths (if stroked). The
4165242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge corrected by
4175242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * using differentials.
4185242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org *
4195242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * The result is device-independent and can be used with any affine matrix.
4205242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org */
4215242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
422249af15fb82833d2274850c589812b6e69df0033joshualittclass DIEllipseEdgeEffect : public GrGeometryProcessor {
4235242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.orgpublic:
4245242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    enum Mode { kStroke = 0, kHairline, kFill };
4255242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
4268059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, Mode mode) {
4278059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        return SkNEW_ARGS(DIEllipseEdgeEffect, (color, viewMatrix, mode));
4285242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    }
4295242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
4305242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    virtual ~DIEllipseEdgeEffect() {}
4315242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
43236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "DIEllipseEdge"; }
4335242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
43471c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inPosition() const { return fInPosition; }
43571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inEllipseOffsets0() const { return fInEllipseOffsets0; }
43671c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* inEllipseOffsets1() const { return fInEllipseOffsets1; }
43788c23fc6e8ed0243159fd17d815b4f813805647bjoshualitt    GrColor color() const { return fColor; }
438e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt    const SkMatrix& viewMatrix() const { return fViewMatrix; }
439249af15fb82833d2274850c589812b6e69df0033joshualitt
4405242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    inline Mode getMode() const { return fMode; }
4415242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
442b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    class GLProcessor : public GrGLGeometryProcessor {
4435242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    public:
444eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        GLProcessor(const GrGeometryProcessor&,
4459b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                    const GrBatchTracker&)
4469b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            : fColor(GrColor_ILLEGAL) {}
4475242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
44836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
4492dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            const DIEllipseEdgeEffect& ee = args.fGP.cast<DIEllipseEdgeEffect>();
4509b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            GrGLGPBuilder* pb = args.fPB;
4519b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            const BatchTracker& local = args.fBT.cast<BatchTracker>();
4522dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
4535242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
454abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit attributes
455abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            vsBuilder->emitAttributes(ee);
456abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
45774077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            GrGLVertToFrag offsets0(kVec2f_GrSLType);
45874077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            args.fPB->addVarying("EllipseOffsets0", &offsets0);
45974077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            vsBuilder->codeAppendf("%s = %s;", offsets0.vsOut(),
4602dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt                                   ee.inEllipseOffsets0()->fName);
46174077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt
46274077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            GrGLVertToFrag offsets1(kVec2f_GrSLType);
46374077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            args.fPB->addVarying("EllipseOffsets1", &offsets1);
46474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            vsBuilder->codeAppendf("%s = %s;", offsets1.vsOut(),
4652dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt                                   ee.inEllipseOffsets1()->fName);
4662dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
4679b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            // Setup pass through color
4689b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
4699b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                                        &fColorUniform);
4709b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
471abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // Setup position
472dd2198701b0ec9da61ecf73418cad03642d715e7joshualitt            this->setupPosition(pb, gpArgs, ee.inPosition()->fName, ee.viewMatrix());
473abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
474abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit transforms
47546d36f0e7b709a077c647841eee23bd3efdc4117robertphillips            this->emitTransforms(args.fPB, gpArgs->fPositionVar, ee.inPosition()->fName,
476e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                                 args.fTransformsIn, args.fTransformsOut);
4774973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
47829bee0fe657fabf7c396502b69c9167fba13eaaaegdaniel            GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
47930ba436f04e61d4505fb854d5fc56079636e0788joshualitt            SkAssertResult(fsBuilder->enableFeature(
48030ba436f04e61d4505fb854d5fc56079636e0788joshualitt                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
4815242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            // for outer curve
48274077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppendf("vec2 scaledOffset = %s.xy;", offsets0.fsIn());
48374077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
48474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s);", offsets0.fsIn());
48574077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s);", offsets0.fsIn());
48674077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppendf("vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
48774077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                                   "                 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
48874077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                                   offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn());
48974077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt
49074077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppend("float grad_dot = dot(grad, grad);");
4911b035d82d2b8b50ae334463edd06e4c5e0639311commit-bot@chromium.org            // avoid calling inversesqrt on zero.
49274077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
49374077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt            fsBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
4942dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            if (kHairline == ee.getMode()) {
4955242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org                // can probably do this with one step
49674077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("float edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);");
49774077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("edgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);");
4985242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            } else {
49974077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
5005242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            }
5015242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5025242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            // for inner curve
5032dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            if (kStroke == ee.getMode()) {
50474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppendf("scaledOffset = %s.xy;", offsets1.fsIn());
50574077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
50674077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppendf("duvdx = dFdx(%s);", offsets1.fsIn());
50774077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppendf("duvdy = dFdy(%s);", offsets1.fsIn());
50874077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppendf("grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
50974077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                                       "            2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
51074077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                                       offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(),
51174077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                                       offsets1.fsIn());
51274077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
51374077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt                fsBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
5145242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            }
5155242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5162dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt            fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
5175242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
5185242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
51946d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        static void GenKey(const GrGeometryProcessor& gp,
5209b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                           const GrBatchTracker& bt,
521cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                           const GrGLSLCaps&,
522b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                           GrProcessorKeyBuilder* b) {
5239b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            const BatchTracker& local = bt.cast<BatchTracker>();
52446d36f0e7b709a077c647841eee23bd3efdc4117robertphillips            const DIEllipseEdgeEffect& ellipseEffect = gp.cast<DIEllipseEdgeEffect>();
5258fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt            uint16_t key = ellipseEffect.getMode();
526e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt            key |= ComputePosKey(ellipseEffect.viewMatrix()) << 9;
5278fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt            b->add32(key << 16 | local.fInputColorType);
5285242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
5295242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5309b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        virtual void setData(const GrGLProgramDataManager& pdman,
5319b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                             const GrPrimitiveProcessor& gp,
53236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                             const GrBatchTracker& bt) override {
533e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt            const DIEllipseEdgeEffect& dee = gp.cast<DIEllipseEdgeEffect>();
534e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt            this->setUniformViewMatrix(pdman, dee.viewMatrix());
535ee2af95db72152dfa61c841875df0594ca93437djoshualitt
5369b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            const BatchTracker& local = bt.cast<BatchTracker>();
5379b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
5389b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                GrGLfloat c[4];
5399b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                GrColorToRGBAFloat(local.fColor, c);
5409b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                pdman.set4fv(fColorUniform, 1, c);
5419b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                fColor = local.fColor;
5429b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            }
5435242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
5445242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5455242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    private:
5469b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrColor fColor;
5479b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        UniformHandle fColorUniform;
5489b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
549249af15fb82833d2274850c589812b6e69df0033joshualitt        typedef GrGLGeometryProcessor INHERITED;
5505242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    };
5515242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
552eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    virtual void getGLProcessorKey(const GrBatchTracker& bt,
553cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                   const GrGLSLCaps& caps,
55436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                                   GrProcessorKeyBuilder* b) const override {
555eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        GLProcessor::GenKey(*this, bt, caps, b);
556eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
557eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
558abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt    virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
559cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                                     const GrGLSLCaps&) const override {
560eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        return SkNEW_ARGS(GLProcessor, (*this, bt));
561eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
562eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
56336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const override {
5649b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        BatchTracker* local = bt->cast<BatchTracker>();
5659b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
566290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt        local->fUsesLocalCoords = init.fUsesLocalCoords;
5679b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    }
5689b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
5695242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.orgprivate:
5708059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    DIEllipseEdgeEffect(GrColor color, const SkMatrix& viewMatrix, Mode mode)
571e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        : fColor(color)
572e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        , fViewMatrix(viewMatrix) {
573eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        this->initClassID<DIEllipseEdgeEffect>();
574c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
575c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco                                                       kHigh_GrSLPrecision));
57671c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt        fInEllipseOffsets0 = &this->addVertexAttrib(Attribute("inEllipseOffsets0",
5772dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt                                                                kVec2f_GrVertexAttribType));
57871c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt        fInEllipseOffsets1 = &this->addVertexAttrib(Attribute("inEllipseOffsets1",
5792dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt                                                                kVec2f_GrVertexAttribType));
5805242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        fMode = mode;
5815242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    }
5825242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5839b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    struct BatchTracker {
5849b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrGPInput fInputColorType;
5859b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrColor fColor;
586290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt        bool fUsesLocalCoords;
5879b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    };
5889b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
58971c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInPosition;
59071c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseOffsets0;
59171c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseOffsets1;
59288c23fc6e8ed0243159fd17d815b4f813805647bjoshualitt    GrColor fColor;
593e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt    SkMatrix fViewMatrix;
5945242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    Mode fMode;
5955242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
596b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
5975242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
598249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGeometryProcessor INHERITED;
5995242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org};
6005242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
601b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseEdgeEffect);
6025242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
603b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrGeometryProcessor* DIEllipseEdgeEffect::TestCreate(SkRandom* random,
604b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                     GrContext* context,
605b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                     const GrDrawTargetCaps&,
606b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                     GrTexture* textures[]) {
6078059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    return DIEllipseEdgeEffect::Create(GrRandomColor(random),
6084eaf9cef5a76098f78efac30beb966ac833d32c2joshualitt                                       GrTest::TestMatrix(random),
6098059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                       (Mode)(random->nextRangeU(0,2)));
6105242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org}
6115242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
6125242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
6135242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
6149853ccef19c200be93a6211f32589fa82a53067cjoshualittbool GrOvalRenderer::drawOval(GrDrawTarget* target,
6158dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                              GrPipelineBuilder* pipelineBuilder,
6162e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt                              GrColor color,
6178059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                              const SkMatrix& viewMatrix,
6189853ccef19c200be93a6211f32589fa82a53067cjoshualitt                              bool useAA,
6199853ccef19c200be93a6211f32589fa82a53067cjoshualitt                              const SkRect& oval,
6209853ccef19c200be93a6211f32589fa82a53067cjoshualitt                              const SkStrokeRec& stroke)
62181312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org{
622ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    bool useCoverageAA = useAA && !pipelineBuilder->getRenderTarget()->isMultisampled();
623e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org
624e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org    if (!useCoverageAA) {
62581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org        return false;
62681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    }
62781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
6287e32851d5473d14db5c396f5877e3dfcb7b19f6dskia.committer@gmail.com    // we can draw circles
6298059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(viewMatrix)) {
6308dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        this->drawCircle(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval, stroke);
6315242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    // if we have shader derivative support, render as device-independent
632e9c0fc616d2a1632c285885b9b656b68ca8d4f24jvanverth    } else if (target->caps()->shaderCaps()->shaderDerivativeSupport()) {
6338dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        return this->drawDIEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
6348059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                   stroke);
6355242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    // otherwise axis-aligned ellipses only
6368059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    } else if (viewMatrix.rectStaysRect()) {
6378dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        return this->drawEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
6388dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                 stroke);
63981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    } else {
64081312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org        return false;
64181312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    }
64281312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
64381312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    return true;
64481312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org}
64581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
646f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
647f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
64876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittclass CircleBatch : public GrBatch {
64976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
65076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct Geometry {
65176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
65276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkMatrix fViewMatrix;
65376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fInnerRadius;
65476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fOuterRadius;
65576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fStroke;
656bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel        SkRect fDevBounds;
65776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
65876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
659ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    static GrBatch* Create(const Geometry& geometry) { return SkNEW_ARGS(CircleBatch, (geometry)); }
66076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
66136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "CircleBatch"; }
66276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
66336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
66476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
66576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setKnownFourComponents(fGeoData[0].fColor);
66676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
66776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
66836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
66976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setUnknownSingleComponent();
67076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
67176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
67236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void initBatchTracker(const GrPipelineInfo& init) override {
67376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Handle any color overrides
67476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (init.fColorIgnored) {
67576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = GrColor_ILLEGAL;
67676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        } else if (GrColor_ILLEGAL != init.fOverrideColor) {
67776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = init.fOverrideColor;
67876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
67976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
68076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // setup batch properties
68176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColorIgnored = init.fColorIgnored;
68276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColor = fGeoData[0].fColor;
68376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fStroke = fGeoData[0].fStroke;
68476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
68576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fCoverageIgnored = init.fCoverageIgnored;
68676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
68776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
68836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
68976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkMatrix invert;
69076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (!this->viewMatrix().invert(&invert)) {
69176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
69276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
69376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
69476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
69576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
69676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                      this->stroke(),
69776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                      invert));
69876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
69976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        batchTarget->initDraw(gp, pipeline);
70076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
70176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO this is hacky, but the only way we have to initialize the GP is to use the
70276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
70376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // everywhere we can remove this nastiness
70476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrPipelineInfo init;
70576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fColorIgnored = fBatch.fColorIgnored;
70676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fOverrideColor = GrColor_ILLEGAL;
70776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fCoverageIgnored = fBatch.fCoverageIgnored;
70876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fUsesLocalCoords = this->usesLocalCoords();
70976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
71076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
71176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
71276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
71376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(vertexStride == sizeof(CircleVertex));
714b5238a7571c243ba4a154a62575570c3078b3741bsalomon        QuadHelper helper;
715b5238a7571c243ba4a154a62575570c3078b3741bsalomon        CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(batchTarget, vertexStride,
716b5238a7571c243ba4a154a62575570c3078b3741bsalomon                                                                          instanceCount));
717b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts) {
7184b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
7194b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
7204b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
72176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
722b5238a7571c243ba4a154a62575570c3078b3741bsalomon            Geometry& geom = fGeoData[i];
72376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
724b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar innerRadius = geom.fInnerRadius;
725b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar outerRadius = geom.fOuterRadius;
72676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
727b5238a7571c243ba4a154a62575570c3078b3741bsalomon            const SkRect& bounds = geom.fDevBounds;
72876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
72976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // The inner radius in the vertex data must be specified in normalized space.
73076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            innerRadius = innerRadius / outerRadius;
73176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
73276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOffset = SkPoint::Make(-1, -1);
73376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOuterRadius = outerRadius;
73476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fInnerRadius = innerRadius;
73576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
73676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
73776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOffset = SkPoint::Make(-1, 1);
73876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOuterRadius = outerRadius;
73976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fInnerRadius = innerRadius;
74076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
74176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
74276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOffset = SkPoint::Make(1, 1);
74376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOuterRadius = outerRadius;
74476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fInnerRadius = innerRadius;
74576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
74676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
74776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOffset = SkPoint::Make(1, -1);
74876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOuterRadius = outerRadius;
74976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fInnerRadius = innerRadius;
75076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
751b5238a7571c243ba4a154a62575570c3078b3741bsalomon            verts += kVerticesPerQuad;
75276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
753e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon        helper.issueDraw(batchTarget);
75476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
75576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
75676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
75776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
75876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittprivate:
75976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    CircleBatch(const Geometry& geometry) {
76076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        this->initClassID<CircleBatch>();
76176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back(geometry);
76299c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt
76399c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->setBounds(geometry.fDevBounds);
76476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
76576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
76636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onCombineIfPossible(GrBatch* t) override {
76776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        CircleBatch* that = t->cast<CircleBatch>();
76876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
76976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO use vertex color to avoid breaking batches
77076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->color() != that->color()) {
77176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
77276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
77376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
77476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->stroke() != that->stroke()) {
77576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
77676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
77776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
77876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
77976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
78076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
78176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
78276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
78376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
78499c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
78576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
78676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
78776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
78876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    GrColor color() const { return fBatch.fColor; }
78976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
79076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
79176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    bool stroke() const { return fBatch.fStroke; }
79276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
79376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct BatchTracker {
79476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
79576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fStroke;
79676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fUsesLocalCoords;
79776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fColorIgnored;
79876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fCoverageIgnored;
79976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
80076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
80176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    BatchTracker fBatch;
80276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
80376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
80476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
8053e708c53f79a04b588b6ca8e535e61f986d80b47joshualittstatic GrBatch* create_circle_batch(GrColor color,
8063e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                    const SkMatrix& viewMatrix,
8073e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                    bool useCoverageAA,
8083e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                    const SkRect& circle,
809d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                    const SkStrokeRec& stroke) {
810972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
8118059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    viewMatrix.mapPoints(&center, 1);
8128059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
8138059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
81481312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
81581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    SkStrokeRec::Style style = stroke.getStyle();
8160a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
8170a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org                        SkStrokeRec::kHairline_Style == style;
8180a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
8197e32851d5473d14db5c396f5877e3dfcb7b19f6dskia.committer@gmail.com
82081312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    SkScalar innerRadius = 0.0f;
82181312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    SkScalar outerRadius = radius;
82281312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    SkScalar halfWidth = 0;
8230a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if (hasStroke) {
82481312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org        if (SkScalarNearlyZero(strokeWidth)) {
82581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org            halfWidth = SK_ScalarHalf;
82681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org        } else {
82781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org            halfWidth = SkScalarHalf(strokeWidth);
82881312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org        }
82981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
83081312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org        outerRadius += halfWidth;
8310a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        if (isStrokeOnly) {
8326bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            innerRadius = radius - halfWidth;
83381312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org        }
83481312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    }
83581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
836ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon    // The radii are outset for two reasons. First, it allows the shader to simply perform simpler
837ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon    // computation because the computed alpha is zero, rather than 50%, at the radius.
838ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon    // Second, the outer radius is used to compute the verts of the bounding box that is rendered
839ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon    // and the outset ensures the box will cover all partially covered by the circle.
84058e30fe8649deb1ffc5bda3627945228b028c439bsalomon@google.com    outerRadius += SK_ScalarHalf;
84158e30fe8649deb1ffc5bda3627945228b028c439bsalomon@google.com    innerRadius -= SK_ScalarHalf;
84258e30fe8649deb1ffc5bda3627945228b028c439bsalomon@google.com
84376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    CircleBatch::Geometry geometry;
84476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fViewMatrix = viewMatrix;
84576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fColor = color;
84676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fInnerRadius = innerRadius;
84776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fOuterRadius = outerRadius;
84876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fStroke = isStrokeOnly && innerRadius > 0;
849d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    geometry.fDevBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
850d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                           center.fX + outerRadius, center.fY + outerRadius);
85176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
8523e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    return CircleBatch::Create(geometry);
8533e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
8543e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
8553e708c53f79a04b588b6ca8e535e61f986d80b47joshualittvoid GrOvalRenderer::drawCircle(GrDrawTarget* target,
8563e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                GrPipelineBuilder* pipelineBuilder,
8573e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                GrColor color,
8583e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                const SkMatrix& viewMatrix,
8593e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                bool useCoverageAA,
8603e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                const SkRect& circle,
8613e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                const SkStrokeRec& stroke) {
8623e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkAutoTUnref<GrBatch> batch(create_circle_batch(color, viewMatrix, useCoverageAA, circle,
863d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                                    stroke));
86499c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt    target->drawBatch(pipelineBuilder, batch);
86581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org}
86681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
867f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
868f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
86976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittclass EllipseBatch : public GrBatch {
87076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
87176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct Geometry {
87276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
87376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkMatrix fViewMatrix;
87476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fXRadius;
87576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fYRadius;
87676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fInnerXRadius;
87776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fInnerYRadius;
87876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fStroke;
879bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel        SkRect fDevBounds;
88076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
88176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
88276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    static GrBatch* Create(const Geometry& geometry) {
88376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return SkNEW_ARGS(EllipseBatch, (geometry));
88476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
88576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
88636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "EllipseBatch"; }
88776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
88836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
88976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
89076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setKnownFourComponents(fGeoData[0].fColor);
89176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
89236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
89376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setUnknownSingleComponent();
89476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
89576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
89636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void initBatchTracker(const GrPipelineInfo& init) override {
89776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Handle any color overrides
89876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (init.fColorIgnored) {
89976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = GrColor_ILLEGAL;
90076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        } else if (GrColor_ILLEGAL != init.fOverrideColor) {
90176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = init.fOverrideColor;
90276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
90376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
90476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // setup batch properties
90576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColorIgnored = init.fColorIgnored;
90676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColor = fGeoData[0].fColor;
90776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fStroke = fGeoData[0].fStroke;
90876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
90976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fCoverageIgnored = init.fCoverageIgnored;
91076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
91176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
91236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
91376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkMatrix invert;
91476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (!this->viewMatrix().invert(&invert)) {
91576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
91676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
91776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
91876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
91976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
92076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                       this->stroke(),
92176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                       invert));
92276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
92376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        batchTarget->initDraw(gp, pipeline);
92476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
92576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO this is hacky, but the only way we have to initialize the GP is to use the
92676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
92776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // everywhere we can remove this nastiness
92876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrPipelineInfo init;
92976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fColorIgnored = fBatch.fColorIgnored;
93076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fOverrideColor = GrColor_ILLEGAL;
93176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fCoverageIgnored = fBatch.fCoverageIgnored;
93276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fUsesLocalCoords = this->usesLocalCoords();
93376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
93476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
93576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
936b5238a7571c243ba4a154a62575570c3078b3741bsalomon        QuadHelper helper;
93776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
93819e0058a650a9e4dc9c35ed26c5e91916bcc0601joshualitt        SkASSERT(vertexStride == sizeof(EllipseVertex));
939b5238a7571c243ba4a154a62575570c3078b3741bsalomon        EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
940b5238a7571c243ba4a154a62575570c3078b3741bsalomon            helper.init(batchTarget, vertexStride, instanceCount));
941b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts) {
9424b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
9434b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
9444b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
94576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
946b5238a7571c243ba4a154a62575570c3078b3741bsalomon            Geometry& geom = fGeoData[i];
94776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
948b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar xRadius = geom.fXRadius;
949b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar yRadius = geom.fYRadius;
95076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
95176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // Compute the reciprocals of the radii here to save time in the shader
95276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xRadRecip = SkScalarInvert(xRadius);
95376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yRadRecip = SkScalarInvert(yRadius);
954b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar xInnerRadRecip = SkScalarInvert(geom.fInnerXRadius);
955b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar yInnerRadRecip = SkScalarInvert(geom.fInnerYRadius);
95676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
957b5238a7571c243ba4a154a62575570c3078b3741bsalomon            const SkRect& bounds = geom.fDevBounds;
95876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
95976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // The inner radius in the vertex data must be specified in normalized space.
96076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
96176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
96276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
96376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
96476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
96576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
96676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOffset = SkPoint::Make(-xRadius, yRadius);
96776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
96876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
96976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
97076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
97176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOffset = SkPoint::Make(xRadius, yRadius);
97276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
97376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
97476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
97576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
97676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOffset = SkPoint::Make(xRadius, -yRadius);
97776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
97876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
97976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
980b5238a7571c243ba4a154a62575570c3078b3741bsalomon            verts += kVerticesPerQuad;
98176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
982e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon        helper.issueDraw(batchTarget);
98376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
98476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
98576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
98676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
98776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittprivate:
98876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    EllipseBatch(const Geometry& geometry) {
98976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        this->initClassID<EllipseBatch>();
99076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back(geometry);
99199c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt
99299c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->setBounds(geometry.fDevBounds);
99376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
99476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
99536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onCombineIfPossible(GrBatch* t) override {
99676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        EllipseBatch* that = t->cast<EllipseBatch>();
99776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
99876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO use vertex color to avoid breaking batches
99976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->color() != that->color()) {
100076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
100176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
100276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
100376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->stroke() != that->stroke()) {
100476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
100576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
100676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
100776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
100876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
100976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
101076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
101176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
101276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
101399c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
101476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
101576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
101676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
101776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    GrColor color() const { return fBatch.fColor; }
101876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
101976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
102076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    bool stroke() const { return fBatch.fStroke; }
102176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
102276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct BatchTracker {
102376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
102476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fStroke;
102576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fUsesLocalCoords;
102676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fColorIgnored;
102776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fCoverageIgnored;
102876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
102976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
103076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    BatchTracker fBatch;
103176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
103276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
103376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
10343e708c53f79a04b588b6ca8e535e61f986d80b47joshualittstatic GrBatch* create_ellipse_batch(GrColor color,
10353e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                     const SkMatrix& viewMatrix,
10363e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                     bool useCoverageAA,
10373e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                     const SkRect& ellipse,
1038d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                     const SkStrokeRec& stroke) {
103981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org#ifdef SK_DEBUG
104081312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    {
104181312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org        // we should have checked for this previously
10428059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        bool isAxisAlignedEllipse = viewMatrix.rectStaysRect();
1043e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org        SkASSERT(useCoverageAA && isAxisAlignedEllipse);
104481312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org    }
104581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org#endif
104681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
10470c888286f7db7e9cd861b2e425a17e109601d3facommit-bot@chromium.org    // do any matrix crunching before we reset the draw state for device coords
1048972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
10498059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    viewMatrix.mapPoints(&center, 1);
10500c888286f7db7e9cd861b2e425a17e109601d3facommit-bot@chromium.org    SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
10510c888286f7db7e9cd861b2e425a17e109601d3facommit-bot@chromium.org    SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
10528059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius +
10538059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                   viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius);
10548059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius +
10558059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                   viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius);
105681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
10570c888286f7db7e9cd861b2e425a17e109601d3facommit-bot@chromium.org    // do (potentially) anisotropic mapping of stroke
10580c888286f7db7e9cd861b2e425a17e109601d3facommit-bot@chromium.org    SkVector scaledStroke;
10590c888286f7db7e9cd861b2e425a17e109601d3facommit-bot@chromium.org    SkScalar strokeWidth = stroke.getWidth();
10608059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
10618059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                               viewMatrix[SkMatrix::kMSkewY]));
10628059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
10638059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                               viewMatrix[SkMatrix::kMScaleY]));
10640c888286f7db7e9cd861b2e425a17e109601d3facommit-bot@chromium.org
10656bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org    SkStrokeRec::Style style = stroke.getStyle();
10660a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
10670a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org                        SkStrokeRec::kHairline_Style == style;
10680a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
10696bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
10705242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    SkScalar innerXRadius = 0;
10715242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    SkScalar innerYRadius = 0;
10720a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if (hasStroke) {
10736bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        if (SkScalarNearlyZero(scaledStroke.length())) {
10746bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
10756bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        } else {
10766bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            scaledStroke.scale(SK_ScalarHalf);
10776bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        }
10786bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
10796bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        // we only handle thick strokes for near-circular ellipses
10806bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        if (scaledStroke.length() > SK_ScalarHalf &&
10816bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
10823e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt            return NULL;
10836bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        }
10846bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
10856bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        // we don't handle it if curvature of the stroke is less than curvature of the ellipse
10866bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
10876bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
10883e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt            return NULL;
10896bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        }
10906bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
10916bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        // this is legit only if scale & translation (which should be the case at the moment)
10920a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        if (isStrokeOnly) {
10936bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            innerXRadius = xRadius - scaledStroke.fX;
10946bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            innerYRadius = yRadius - scaledStroke.fY;
10956bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        }
10966bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
10976bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        xRadius += scaledStroke.fX;
10986bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        yRadius += scaledStroke.fY;
10996bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org    }
11006bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
11010a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org    // We've extended the outer x radius out half a pixel to antialias.
11020a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org    // This will also expand the rect so all the pixels will be captured.
11036bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org    // TODO: Consider if we should use sqrt(2)/2 instead
11040a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org    xRadius += SK_ScalarHalf;
11050a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org    yRadius += SK_ScalarHalf;
11060a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org
110776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    EllipseBatch::Geometry geometry;
110876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fViewMatrix = viewMatrix;
110976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fColor = color;
111076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fXRadius = xRadius;
111176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fYRadius = yRadius;
111276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fInnerXRadius = innerXRadius;
111376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fInnerYRadius = innerYRadius;
111476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fStroke = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
1115d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    geometry.fDevBounds = SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius,
1116d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                           center.fX + xRadius, center.fY + yRadius);
111781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
11183e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    return EllipseBatch::Create(geometry);
11193e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
11200a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org
11213e708c53f79a04b588b6ca8e535e61f986d80b47joshualittbool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
11223e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                 GrPipelineBuilder* pipelineBuilder,
11233e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                 GrColor color,
11243e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                 const SkMatrix& viewMatrix,
11253e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                 bool useCoverageAA,
11263e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                 const SkRect& ellipse,
11273e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                 const SkStrokeRec& stroke) {
11283e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkAutoTUnref<GrBatch> batch(create_ellipse_batch(color, viewMatrix, useCoverageAA, ellipse,
1129d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                                     stroke));
11303e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    if (!batch) {
11313e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt        return false;
11323e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
11333e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
113499c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt    target->drawBatch(pipelineBuilder, batch);
113576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    return true;
113676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt}
11370a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org
113876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt/////////////////////////////////////////////////////////////////////////////////////////////////
11394674676438051c31a991fdab72efea3c7d0ca5a3skia.committer@gmail.com
114076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittclass DIEllipseBatch : public GrBatch {
114176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
114276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct Geometry {
114376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
114476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkMatrix fViewMatrix;
114576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fXRadius;
114676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fYRadius;
114776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fInnerXRadius;
114876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fInnerYRadius;
114976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fGeoDx;
115076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fGeoDy;
115176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        DIEllipseEdgeEffect::Mode fMode;
11529ef1bb1375e66d9aac1124e005b500cb6d9caf01egdaniel        SkRect fBounds;
115376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
1154c4f2ecaa475756bda48684b1158ec6b8bbdd1016jvanverth@google.com
115599c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt    static GrBatch* Create(const Geometry& geometry, const SkRect& bounds) {
115699c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        return SkNEW_ARGS(DIEllipseBatch, (geometry, bounds));
115776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
115876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
115936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "DIEllipseBatch"; }
116076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
116136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
116276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
116376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setKnownFourComponents(fGeoData[0].fColor);
116476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
116536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
116676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setUnknownSingleComponent();
116776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
116876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
116936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void initBatchTracker(const GrPipelineInfo& init) override {
117076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Handle any color overrides
117176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (init.fColorIgnored) {
117276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = GrColor_ILLEGAL;
117376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        } else if (GrColor_ILLEGAL != init.fOverrideColor) {
117476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = init.fOverrideColor;
117576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
117676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
117776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // setup batch properties
117876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColorIgnored = init.fColorIgnored;
117976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColor = fGeoData[0].fColor;
118076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fMode = fGeoData[0].fMode;
118176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
118276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fCoverageIgnored = init.fCoverageIgnored;
118376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
118476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
118536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
118676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
118776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(this->color(),
118876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                         this->viewMatrix(),
118976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                         this->mode()));
119076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
119176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        batchTarget->initDraw(gp, pipeline);
119276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
119376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO this is hacky, but the only way we have to initialize the GP is to use the
119476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
119576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // everywhere we can remove this nastiness
119676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrPipelineInfo init;
119776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fColorIgnored = fBatch.fColorIgnored;
119876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fOverrideColor = GrColor_ILLEGAL;
119976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fCoverageIgnored = fBatch.fCoverageIgnored;
120076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fUsesLocalCoords = this->usesLocalCoords();
120176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
120276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
120376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
120476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
120519e0058a650a9e4dc9c35ed26c5e91916bcc0601joshualitt        SkASSERT(vertexStride == sizeof(DIEllipseVertex));
1206b5238a7571c243ba4a154a62575570c3078b3741bsalomon        QuadHelper helper;
1207b5238a7571c243ba4a154a62575570c3078b3741bsalomon        DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(
1208b5238a7571c243ba4a154a62575570c3078b3741bsalomon            helper.init(batchTarget, vertexStride, instanceCount));
1209b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts) {
12104b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
12114b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
12124b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
121376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
1214b5238a7571c243ba4a154a62575570c3078b3741bsalomon            Geometry& geom = fGeoData[i];
121576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1216b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar xRadius = geom.fXRadius;
1217b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar yRadius = geom.fYRadius;
121876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1219b5238a7571c243ba4a154a62575570c3078b3741bsalomon            const SkRect& bounds = geom.fBounds;
122076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
122176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // This adjusts the "radius" to include the half-pixel border
122280ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar offsetDx = geom.fGeoDx / xRadius;
122380ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar offsetDy = geom.fGeoDy / yRadius;
122476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
122580ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar innerRatioX = xRadius / geom.fInnerXRadius;
122680ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar innerRatioY = yRadius / geom.fInnerYRadius;
122776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
122876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
122976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
123076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
123176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
123276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
123376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
123476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
123576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
123676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
123776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
123876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
123976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
124076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
124176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
124276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
124376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1244b5238a7571c243ba4a154a62575570c3078b3741bsalomon            verts += kVerticesPerQuad;
124576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
1246e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon        helper.issueDraw(batchTarget);
124776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
124876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
124976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
125076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
125176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittprivate:
125299c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt    DIEllipseBatch(const Geometry& geometry, const SkRect& bounds) {
125376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        this->initClassID<DIEllipseBatch>();
125476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back(geometry);
125599c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt
125699c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->setBounds(bounds);
125776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
125876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
125936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onCombineIfPossible(GrBatch* t) override {
126076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        DIEllipseBatch* that = t->cast<DIEllipseBatch>();
126176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
126276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO use vertex color to avoid breaking batches
126376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->color() != that->color()) {
126476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
126576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
126676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
126776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->mode() != that->mode()) {
126876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
126976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
127076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1271d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        // TODO rewrite to allow positioning on CPU
1272d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
127376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
127476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
127576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
127676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
127799c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
127876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
127976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
128076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
128176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    GrColor color() const { return fBatch.fColor; }
128276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
128376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
128476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    DIEllipseEdgeEffect::Mode mode() const { return fBatch.fMode; }
128576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
128676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct BatchTracker {
128776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
128876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        DIEllipseEdgeEffect::Mode fMode;
128976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fUsesLocalCoords;
129076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fColorIgnored;
129176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fCoverageIgnored;
129276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
129376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
129476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    BatchTracker fBatch;
129576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
129676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
1297f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
12983e708c53f79a04b588b6ca8e535e61f986d80b47joshualittstatic GrBatch* create_diellipse_batch(GrColor color,
12993e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                       const SkMatrix& viewMatrix,
13003e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                       bool useCoverageAA,
13013e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                       const SkRect& ellipse,
1302d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                       const SkStrokeRec& stroke) {
1303972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
13045242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    SkScalar xRadius = SkScalarHalf(ellipse.width());
13056fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.com    SkScalar yRadius = SkScalarHalf(ellipse.height());
13066fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.com
13075242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    SkStrokeRec::Style style = stroke.getStyle();
13086fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.com    DIEllipseEdgeEffect::Mode mode = (SkStrokeRec::kStroke_Style == style) ?
13095242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org                                    DIEllipseEdgeEffect::kStroke :
13106fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.com                                    (SkStrokeRec::kHairline_Style == style) ?
13115242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org                                    DIEllipseEdgeEffect::kHairline : DIEllipseEdgeEffect::kFill;
13125242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
13135242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    SkScalar innerXRadius = 0;
13145242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    SkScalar innerYRadius = 0;
13155242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
13165242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        SkScalar strokeWidth = stroke.getWidth();
13175242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
13185242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        if (SkScalarNearlyZero(strokeWidth)) {
13195242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            strokeWidth = SK_ScalarHalf;
13205242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        } else {
13215242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            strokeWidth *= SK_ScalarHalf;
13225242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
13235242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
13245242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        // we only handle thick strokes for near-circular ellipses
13255242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        if (strokeWidth > SK_ScalarHalf &&
13265242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
13273e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt            return NULL;
13285242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
13295242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
13305242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        // we don't handle it if curvature of the stroke is less than curvature of the ellipse
13315242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
13325242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
13333e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt            return NULL;
13345242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
13355242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
13365242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        // set inner radius (if needed)
13375242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        if (SkStrokeRec::kStroke_Style == style) {
13385242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            innerXRadius = xRadius - strokeWidth;
13395242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            innerYRadius = yRadius - strokeWidth;
13405242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
13415242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
13425242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        xRadius += strokeWidth;
13435242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        yRadius += strokeWidth;
13445242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    }
13455242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    if (DIEllipseEdgeEffect::kStroke == mode) {
13465242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kStroke :
13475242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org                                                        DIEllipseEdgeEffect::kFill;
13485242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    }
13495242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
13505242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    // This expands the outer rect so that after CTM we end up with a half-pixel border
13518059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar a = viewMatrix[SkMatrix::kMScaleX];
13528059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar b = viewMatrix[SkMatrix::kMSkewX];
13538059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar c = viewMatrix[SkMatrix::kMSkewY];
13548059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar d = viewMatrix[SkMatrix::kMScaleY];
135580ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed    SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
135680ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed    SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
13575242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
135876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    DIEllipseBatch::Geometry geometry;
135976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fViewMatrix = viewMatrix;
136076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fColor = color;
136176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fXRadius = xRadius;
136276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fYRadius = yRadius;
136376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fInnerXRadius = innerXRadius;
136476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fInnerYRadius = innerYRadius;
136576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fGeoDx = geoDx;
136676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fGeoDy = geoDy;
136776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    geometry.fMode = mode;
1368d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    geometry.fBounds = SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
1369d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                        center.fX + xRadius + geoDx, center.fY + yRadius + geoDy);
13709ef1bb1375e66d9aac1124e005b500cb6d9caf01egdaniel
1371d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    SkRect devBounds = geometry.fBounds;
1372d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    viewMatrix.mapRect(&devBounds);
1373d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    return DIEllipseBatch::Create(geometry, devBounds);
13743e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
137576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
13763e708c53f79a04b588b6ca8e535e61f986d80b47joshualittbool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
13773e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                   GrPipelineBuilder* pipelineBuilder,
13783e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                   GrColor color,
13793e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                   const SkMatrix& viewMatrix,
13803e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                   bool useCoverageAA,
13813e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                   const SkRect& ellipse,
13823e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                   const SkStrokeRec& stroke) {
13833e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkAutoTUnref<GrBatch> batch(create_diellipse_batch(color, viewMatrix, useCoverageAA, ellipse,
1384d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                                       stroke));
13853e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    if (!batch) {
13863e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt        return false;
13873e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
138899c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt    target->drawBatch(pipelineBuilder, batch);
13895242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    return true;
13905242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org}
13915242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
1392f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
1393f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1394f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.orgstatic const uint16_t gRRectIndices[] = {
1395f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // corners
1396f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    0, 1, 5, 0, 5, 4,
1397f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    2, 3, 7, 2, 7, 6,
1398f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    8, 9, 13, 8, 13, 12,
1399f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    10, 11, 15, 10, 15, 14,
14002cf444f7040614b43af67e368f3aa636ebeaa45askia.committer@gmail.com
1401f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // edges
1402f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    1, 2, 6, 1, 6, 5,
1403f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    4, 5, 9, 4, 9, 8,
1404f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    6, 7, 11, 6, 11, 10,
1405f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    9, 10, 14, 9, 14, 13,
14062cf444f7040614b43af67e368f3aa636ebeaa45askia.committer@gmail.com
1407f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // center
1408f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // we place this at the end so that we can ignore these indices when rendering stroke-only
1409f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    5, 6, 10, 5, 10, 9
1410f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org};
1411f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
14125ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIndicesPerStrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
14135ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIndicesPerRRect = SK_ARRAY_COUNT(gRRectIndices);
14145ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kVertsPerRRect = 16;
14155ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kNumRRectsInIndexBuffer = 256;
14165ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt
1417ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonGR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1418ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonGR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1419ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic const GrIndexBuffer* ref_rrect_index_buffer(bool strokeOnly,
1420ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                                   GrResourceProvider* resourceProvider) {
1421ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1422ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1423ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    if (strokeOnly) {
1424ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        return resourceProvider->refOrCreateInstancedIndexBuffer(
1425ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            gRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1426ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            gStrokeRRectOnlyIndexBufferKey);
1427ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    } else {
1428ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        return resourceProvider->refOrCreateInstancedIndexBuffer(
1429ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            gRRectIndices, kIndicesPerRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1430ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            gRRectOnlyIndexBufferKey);
1431ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon
1432ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    }
1433ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon}
1434ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon
14359853ccef19c200be93a6211f32589fa82a53067cjoshualittbool GrOvalRenderer::drawDRRect(GrDrawTarget* target,
14368dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                GrPipelineBuilder* pipelineBuilder,
14372e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt                                GrColor color,
14388059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                const SkMatrix& viewMatrix,
14399853ccef19c200be93a6211f32589fa82a53067cjoshualitt                                bool useAA,
14409853ccef19c200be93a6211f32589fa82a53067cjoshualitt                                const SkRRect& origOuter,
14419853ccef19c200be93a6211f32589fa82a53067cjoshualitt                                const SkRRect& origInner) {
14428af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    bool applyAA = useAA &&
14430bdeec9640640922eb6b0a9f798bcd85eb898f29egdaniel                   !pipelineBuilder->getRenderTarget()->isMultisampled();
14446be6f7cb66b277e7b1ce13d09b635fb8e09a2f68bsalomon    GrPipelineBuilder::AutoRestoreFragmentProcessors arfp;
14450a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if (!origInner.isEmpty()) {
14460a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        SkTCopyOnFirstWrite<SkRRect> inner(origInner);
14478059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        if (!viewMatrix.isIdentity()) {
14488059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            if (!origInner.transform(viewMatrix, inner.writable())) {
14490a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org                return false;
14500a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org            }
14510a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        }
1452b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        GrPrimitiveEdgeType edgeType = applyAA ?
1453b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                kInverseFillAA_GrProcessorEdgeType :
1454b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                kInverseFillBW_GrProcessorEdgeType;
14552e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt        // TODO this needs to be a geometry processor
1456b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        GrFragmentProcessor* fp = GrRRectEffect::Create(edgeType, *inner);
1457b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        if (NULL == fp) {
14580a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org            return false;
14590a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        }
14606be6f7cb66b277e7b1ce13d09b635fb8e09a2f68bsalomon        arfp.set(pipelineBuilder);
14618dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        pipelineBuilder->addCoverageProcessor(fp)->unref();
14620a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    }
14630a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
14640a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle);
14658dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    if (this->drawRRect(target, pipelineBuilder, color, viewMatrix, useAA, origOuter, fillRec)) {
14668af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon        return true;
14678af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    }
14688af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon
14698af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    SkASSERT(!origOuter.isEmpty());
14708af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    SkTCopyOnFirstWrite<SkRRect> outer(origOuter);
14718059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    if (!viewMatrix.isIdentity()) {
14728059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        if (!origOuter.transform(viewMatrix, outer.writable())) {
14738af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon            return false;
14748af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon        }
14758af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    }
1476b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrPrimitiveEdgeType edgeType = applyAA ? kFillAA_GrProcessorEdgeType :
147776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                             kFillBW_GrProcessorEdgeType;
1478b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrFragmentProcessor* effect = GrRRectEffect::Create(edgeType, *outer);
14798af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    if (NULL == effect) {
14808af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon        return false;
14818af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    }
14826be6f7cb66b277e7b1ce13d09b635fb8e09a2f68bsalomon    if (!arfp.isSet()) {
14836be6f7cb66b277e7b1ce13d09b635fb8e09a2f68bsalomon        arfp.set(pipelineBuilder);
14848af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    }
1485d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt
1486d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt    SkMatrix invert;
14878059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    if (!viewMatrix.invert(&invert)) {
14888af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon        return false;
14898af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    }
1490d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt
14918dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    pipelineBuilder->addCoverageProcessor(effect)->unref();
14928af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    SkRect bounds = outer->getBounds();
14938af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    if (applyAA) {
14948af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
14958af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    }
14968dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    target->drawRect(pipelineBuilder, color, SkMatrix::I(), bounds, NULL, &invert);
14978af0523b38f25993c8b1ba3a3562b9f9ac87162dbsalomon    return true;
14980a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org}
14990a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
150076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt///////////////////////////////////////////////////////////////////////////////////////////////////
150176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
150276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittclass RRectCircleRendererBatch : public GrBatch {
150376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
150476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct Geometry {
150576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
150676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkMatrix fViewMatrix;
150776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fInnerRadius;
150876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fOuterRadius;
150976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fStroke;
1510bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel        SkRect fDevBounds;
151176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
151276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1513ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    static GrBatch* Create(const Geometry& geometry) {
1514ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        return SkNEW_ARGS(RRectCircleRendererBatch, (geometry));
151576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
151676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
151736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "RRectCircleBatch"; }
151876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
151936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
152076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
152176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setKnownFourComponents(fGeoData[0].fColor);
152276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
152336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
152476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setUnknownSingleComponent();
152576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
152676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
152736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void initBatchTracker(const GrPipelineInfo& init) override {
152876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Handle any color overrides
152976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (init.fColorIgnored) {
153076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = GrColor_ILLEGAL;
153176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        } else if (GrColor_ILLEGAL != init.fOverrideColor) {
153276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = init.fOverrideColor;
153376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
153476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
153576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // setup batch properties
153676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColorIgnored = init.fColorIgnored;
153776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColor = fGeoData[0].fColor;
153876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fStroke = fGeoData[0].fStroke;
153976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
154076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fCoverageIgnored = init.fCoverageIgnored;
154176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
154276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
154336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
154476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // reset to device coordinates
154576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkMatrix invert;
154676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (!this->viewMatrix().invert(&invert)) {
154776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkDebugf("Failed to invert\n");
154876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
154976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
155076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
155176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
155276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
155376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                      this->stroke(),
155476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                      invert));
155576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
155676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        batchTarget->initDraw(gp, pipeline);
155776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
155876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO this is hacky, but the only way we have to initialize the GP is to use the
155976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
156076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // everywhere we can remove this nastiness
156176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrPipelineInfo init;
156276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fColorIgnored = fBatch.fColorIgnored;
156376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fOverrideColor = GrColor_ILLEGAL;
156476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fCoverageIgnored = fBatch.fCoverageIgnored;
156576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fUsesLocalCoords = this->usesLocalCoords();
156676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
156776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
156876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
156976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
157076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(vertexStride == sizeof(CircleVertex));
157176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1572b5238a7571c243ba4a154a62575570c3078b3741bsalomon        // drop out the middle quad if we're stroked
1573b5238a7571c243ba4a154a62575570c3078b3741bsalomon        int indicesPerInstance = this->stroke() ? kIndicesPerStrokeRRect : kIndicesPerRRect;
1574ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
1575ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            ref_rrect_index_buffer(this->stroke(), batchTarget->resourceProvider()));
157676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1577b5238a7571c243ba4a154a62575570c3078b3741bsalomon        InstancedHelper helper;
1578b5238a7571c243ba4a154a62575570c3078b3741bsalomon        CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(batchTarget,
1579b5238a7571c243ba4a154a62575570c3078b3741bsalomon            kTriangles_GrPrimitiveType, vertexStride, indexBuffer, kVertsPerRRect,
1580b5238a7571c243ba4a154a62575570c3078b3741bsalomon            indicesPerInstance, instanceCount));
1581b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts || !indexBuffer) {
15824b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            SkDebugf("Could not allocate vertices\n");
15834b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
15844b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
15854b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
158676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
158776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            Geometry& args = fGeoData[i];
158876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
158976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar outerRadius = args.fOuterRadius;
159076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1591bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel            const SkRect& bounds = args.fDevBounds;
159276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
159376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yCoords[4] = {
159476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fTop,
159576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fTop + outerRadius,
159676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fBottom - outerRadius,
159776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fBottom
159876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            };
159976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
160076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
160176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // The inner radius in the vertex data must be specified in normalized space.
160276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar innerRadius = args.fInnerRadius / args.fOuterRadius;
160376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            for (int i = 0; i < 4; ++i) {
160476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
160576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
160676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
160776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
160876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
160976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
161076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
161176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
161276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
161376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
161476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
161576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
161676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
161776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
161876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
161976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
162076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
162176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
162276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
162376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
162476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
162576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
162676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
162776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            }
162876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
162976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1630e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon        helper.issueDraw(batchTarget);
163176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
163276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
163376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
163476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
163576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittprivate:
1636ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    RRectCircleRendererBatch(const Geometry& geometry) {
163776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        this->initClassID<RRectCircleRendererBatch>();
163876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back(geometry);
163999c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt
164099c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->setBounds(geometry.fDevBounds);
164176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
164276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
164336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onCombineIfPossible(GrBatch* t) override {
164476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>();
164576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
164676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO use vertex color to avoid breaking batches
164776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->color() != that->color()) {
164876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
164976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
165076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
165176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->stroke() != that->stroke()) {
165276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
165376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
165476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
165576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
165676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
165776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
165876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
165976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
166076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
166199c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
166276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
166376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
166476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
166576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    GrColor color() const { return fBatch.fColor; }
166676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
166776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
166876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    bool stroke() const { return fBatch.fStroke; }
166976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
167076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct BatchTracker {
167176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
167276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fStroke;
167376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fUsesLocalCoords;
167476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fColorIgnored;
167576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fCoverageIgnored;
167676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
167776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
167876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    BatchTracker fBatch;
167976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
168076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
168176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
168276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittclass RRectEllipseRendererBatch : public GrBatch {
168376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
168476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct Geometry {
168576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
168676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkMatrix fViewMatrix;
168776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fXRadius;
168876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fYRadius;
168976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fInnerXRadius;
169076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkScalar fInnerYRadius;
169176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fStroke;
1692bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel        SkRect fDevBounds;
169376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
169476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1695ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    static GrBatch* Create(const Geometry& geometry) {
1696ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        return SkNEW_ARGS(RRectEllipseRendererBatch, (geometry));
169776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
169876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
169936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "RRectEllipseRendererBatch"; }
170076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
170136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
170276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // When this is called on a batch, there is only one geometry bundle
170376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setKnownFourComponents(fGeoData[0].fColor);
170476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
170536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
170676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        out->setUnknownSingleComponent();
170776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
170876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
170936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void initBatchTracker(const GrPipelineInfo& init) override {
171076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Handle any color overrides
171176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (init.fColorIgnored) {
171276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = GrColor_ILLEGAL;
171376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        } else if (GrColor_ILLEGAL != init.fOverrideColor) {
171476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            fGeoData[0].fColor = init.fOverrideColor;
171576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
171676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
171776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // setup batch properties
171876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColorIgnored = init.fColorIgnored;
171976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fColor = fGeoData[0].fColor;
172076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fStroke = fGeoData[0].fStroke;
172176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
172276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fBatch.fCoverageIgnored = init.fCoverageIgnored;
172376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
172476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
172536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
172676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // reset to device coordinates
172776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkMatrix invert;
172876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (!this->viewMatrix().invert(&invert)) {
172976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkDebugf("Failed to invert\n");
173076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
173176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
173276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
173376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
173476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
173576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                       this->stroke(),
173676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                                                                       invert));
173776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
173876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        batchTarget->initDraw(gp, pipeline);
173976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
174076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO this is hacky, but the only way we have to initialize the GP is to use the
174176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
174276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // everywhere we can remove this nastiness
174376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrPipelineInfo init;
174476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fColorIgnored = fBatch.fColorIgnored;
174576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fOverrideColor = GrColor_ILLEGAL;
174676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fCoverageIgnored = fBatch.fCoverageIgnored;
174776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        init.fUsesLocalCoords = this->usesLocalCoords();
174876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
174976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
175076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
175176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
175276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(vertexStride == sizeof(EllipseVertex));
175376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1754b5238a7571c243ba4a154a62575570c3078b3741bsalomon        // drop out the middle quad if we're stroked
1755b5238a7571c243ba4a154a62575570c3078b3741bsalomon        int indicesPerInstance = this->stroke() ? kIndicesPerStrokeRRect : kIndicesPerRRect;
1756ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
1757ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            ref_rrect_index_buffer(this->stroke(), batchTarget->resourceProvider()));
175876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1759b5238a7571c243ba4a154a62575570c3078b3741bsalomon        InstancedHelper helper;
1760b5238a7571c243ba4a154a62575570c3078b3741bsalomon        EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
1761b5238a7571c243ba4a154a62575570c3078b3741bsalomon            helper.init(batchTarget, kTriangles_GrPrimitiveType, vertexStride, indexBuffer,
1762b5238a7571c243ba4a154a62575570c3078b3741bsalomon            kVertsPerRRect, indicesPerInstance, instanceCount));
1763b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts || !indexBuffer) {
17644b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            SkDebugf("Could not allocate vertices\n");
17654b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
17664b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
17674b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
176876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
176976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            Geometry& args = fGeoData[i];
177076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
177176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // Compute the reciprocals of the radii here to save time in the shader
177276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
177376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yRadRecip = SkScalarInvert(args.fYRadius);
177476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
177576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
177676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
177776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // Extend the radii out half a pixel to antialias.
177876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xOuterRadius = args.fXRadius + SK_ScalarHalf;
177976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yOuterRadius = args.fYRadius + SK_ScalarHalf;
178076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1781bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel            const SkRect& bounds = args.fDevBounds;
178276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
178376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yCoords[4] = {
178476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fTop,
178576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fTop + yOuterRadius,
178676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fBottom - yOuterRadius,
178776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                bounds.fBottom
178876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            };
178976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yOuterOffsets[4] = {
179076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                yOuterRadius,
179176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                SK_ScalarNearlyZero, // we're using inversesqrt() in shader, so can't be exactly 0
179276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                SK_ScalarNearlyZero,
179376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                yOuterRadius
179476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            };
179576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
179676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            for (int i = 0; i < 4; ++i) {
179776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
179876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
179976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
180076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
180176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
180276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
180376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
180476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
180576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
180676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
180776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
180876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
180976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
181076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
181176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
181276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
181376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
181476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
181576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
181676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
181776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
181876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
181976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
182076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            }
182176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
1822e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon        helper.issueDraw(batchTarget);
182376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
182476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
182576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
182676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
182776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittprivate:
1828ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    RRectEllipseRendererBatch(const Geometry& geometry) {
182976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        this->initClassID<RRectEllipseRendererBatch>();
183076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back(geometry);
183199c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt
183299c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->setBounds(geometry.fDevBounds);
183376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
183476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
183536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onCombineIfPossible(GrBatch* t) override {
183676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        RRectEllipseRendererBatch* that = t->cast<RRectEllipseRendererBatch>();
183776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
183876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // TODO use vertex color to avoid breaking batches
183976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->color() != that->color()) {
184076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
184176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
184276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
184376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->stroke() != that->stroke()) {
184476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
184576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
184676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
184776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
184876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
184976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
185076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
185176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
185276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
185399c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
185476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
185576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
185676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
185776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    GrColor color() const { return fBatch.fColor; }
185876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
185976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
186076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    bool stroke() const { return fBatch.fStroke; }
186176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
186276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    struct BatchTracker {
186376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        GrColor fColor;
186476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fStroke;
186576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fUsesLocalCoords;
186676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fColorIgnored;
186776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        bool fCoverageIgnored;
186876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    };
186976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
187076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    BatchTracker fBatch;
187176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
187276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
187376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
18743e708c53f79a04b588b6ca8e535e61f986d80b47joshualittstatic GrBatch* create_rrect_batch(GrColor color,
18753e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                   const SkMatrix& viewMatrix,
18763e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                                   const SkRRect& rrect,
1877d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt                                   const SkStrokeRec& stroke) {
18783e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkASSERT(viewMatrix.rectStaysRect());
18793e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkASSERT(rrect.isSimple());
18803e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkASSERT(!rrect.isOval());
18813e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
18823e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    // RRect batchs only handle simple, but not too simple, rrects
1883f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // do any matrix crunching before we reset the draw state for device coords
1884f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    const SkRect& rrectBounds = rrect.getBounds();
1885d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    SkRect bounds;
1886d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    viewMatrix.mapRect(&bounds, rrectBounds);
1887f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1888f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkVector radii = rrect.getSimpleRadii();
18898059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX +
18908059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                   viewMatrix[SkMatrix::kMSkewY]*radii.fY);
18918059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX +
18928059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                   viewMatrix[SkMatrix::kMScaleY]*radii.fY);
18936bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
1894f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkStrokeRec::Style style = stroke.getStyle();
1895f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1896f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // do (potentially) anisotropic mapping of stroke
1897f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkVector scaledStroke;
1898f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkScalar strokeWidth = stroke.getWidth();
1899f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
19000a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
19010a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org                        SkStrokeRec::kHairline_Style == style;
19020a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
19030a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
19040a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if (hasStroke) {
19050a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        if (SkStrokeRec::kHairline_Style == style) {
19060a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org            scaledStroke.set(1, 1);
19070a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        } else {
19088059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
19098059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                                       viewMatrix[SkMatrix::kMSkewY]));
19108059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
19118059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                                       viewMatrix[SkMatrix::kMScaleY]));
19120a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        }
19130a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
19140a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        // if half of strokewidth is greater than radius, we don't handle that right now
19150a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) {
19163e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt            return NULL;
19170a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        }
19180a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    }
19190a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
19200a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
19210a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
19220a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // patch will have fractional coverage. This only matters when the interior is actually filled.
19230a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // We could consider falling back to rect rendering here, since a tiny radius is
19240a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // indistinguishable from a square corner.
19250a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
19263e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt        return NULL;
1927f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    }
1928f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1929f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // if the corners are circles, use the circle renderer
19300a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
1931f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        SkScalar innerRadius = 0.0f;
1932f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        SkScalar outerRadius = xRadius;
1933f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        SkScalar halfWidth = 0;
19340a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        if (hasStroke) {
1935f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            if (SkScalarNearlyZero(scaledStroke.fX)) {
1936f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org                halfWidth = SK_ScalarHalf;
1937f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            } else {
1938f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org                halfWidth = SkScalarHalf(scaledStroke.fX);
1939f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            }
19402cf444f7040614b43af67e368f3aa636ebeaa45askia.committer@gmail.com
19410a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org            if (isStrokeOnly) {
19426bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org                innerRadius = xRadius - halfWidth;
1943f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            }
1944f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            outerRadius += halfWidth;
1945d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt            bounds.outset(halfWidth, halfWidth);
1946f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        }
19472cf444f7040614b43af67e368f3aa636ebeaa45askia.committer@gmail.com
19480a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
1949cefde6e5783bcce27369216e5e4ee5c7eed02e26commit-bot@chromium.org
1950f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        // The radii are outset for two reasons. First, it allows the shader to simply perform
1951ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
1952ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon        // Second, the outer radius is used to compute the verts of the bounding box that is
1953ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon        // rendered and the outset ensures the box will cover all partially covered by the rrect
1954ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon        // corners.
1955f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        outerRadius += SK_ScalarHalf;
1956f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        innerRadius -= SK_ScalarHalf;
19572cf444f7040614b43af67e368f3aa636ebeaa45askia.committer@gmail.com
1958f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        // Expand the rect so all the pixels will be captured.
1959d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
19602cf444f7040614b43af67e368f3aa636ebeaa45askia.committer@gmail.com
196176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        RRectCircleRendererBatch::Geometry geometry;
196276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fViewMatrix = viewMatrix;
196376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fColor = color;
196476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fInnerRadius = innerRadius;
196576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fOuterRadius = outerRadius;
196676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fStroke = isStrokeOnly;
1967d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        geometry.fDevBounds = bounds;
19682cf444f7040614b43af67e368f3aa636ebeaa45askia.committer@gmail.com
1969ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        return RRectCircleRendererBatch::Create(geometry);
19706bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org    // otherwise we use the ellipse renderer
1971f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    } else {
1972f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        SkScalar innerXRadius = 0.0f;
1973f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        SkScalar innerYRadius = 0.0f;
19740a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        if (hasStroke) {
1975f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            if (SkScalarNearlyZero(scaledStroke.length())) {
1976f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org                scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1977f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            } else {
19786bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org                scaledStroke.scale(SK_ScalarHalf);
19796bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            }
19806bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
19816bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            // we only handle thick strokes for near-circular ellipses
19828be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com            if (scaledStroke.length() > SK_ScalarHalf &&
19836bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org                (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
19843e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                return NULL;
19856bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            }
19866bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
19876bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
19886bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
19896bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org                scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
19903e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                return NULL;
1991f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            }
1992f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1993f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            // this is legit only if scale & translation (which should be the case at the moment)
19940a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org            if (isStrokeOnly) {
19956bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org                innerXRadius = xRadius - scaledStroke.fX;
19966bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org                innerYRadius = yRadius - scaledStroke.fY;
1997f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            }
19986bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
1999f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            xRadius += scaledStroke.fX;
2000f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org            yRadius += scaledStroke.fY;
2001d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt            bounds.outset(scaledStroke.fX, scaledStroke.fY);
2002f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        }
2003f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
20040a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
2005cefde6e5783bcce27369216e5e4ee5c7eed02e26commit-bot@chromium.org
2006f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org        // Expand the rect so all the pixels will be captured.
2007d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
2008f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
200976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        RRectEllipseRendererBatch::Geometry geometry;
201076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fViewMatrix = viewMatrix;
201176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fColor = color;
201276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fXRadius = xRadius;
201376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fYRadius = yRadius;
201476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fInnerXRadius = innerXRadius;
201576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fInnerYRadius = innerYRadius;
201676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        geometry.fStroke = isStrokeOnly;
2017d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        geometry.fDevBounds = bounds;
201876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2019ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        return RRectEllipseRendererBatch::Create(geometry);
2020f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    }
20213e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
20223e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20233e708c53f79a04b588b6ca8e535e61f986d80b47joshualittbool GrOvalRenderer::drawRRect(GrDrawTarget* target,
20243e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                               GrPipelineBuilder* pipelineBuilder,
20253e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                               GrColor color,
20263e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                               const SkMatrix& viewMatrix,
20273e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                               bool useAA,
20283e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                               const SkRRect& rrect,
20293e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                               const SkStrokeRec& stroke) {
20303e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    if (rrect.isOval()) {
20313e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt        return this->drawOval(target, pipelineBuilder, color, viewMatrix, useAA, rrect.getBounds(),
20323e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt                              stroke);
20333e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
20343e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20353e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    bool useCoverageAA = useAA && !pipelineBuilder->getRenderTarget()->isMultisampled();
20363e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20373e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    // only anti-aliased rrects for now
20383e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    if (!useCoverageAA) {
20393e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt        return false;
20403e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
20413e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20423e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
20433e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt        return false;
20443e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
20453e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
2046d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    SkAutoTUnref<GrBatch> batch(create_rrect_batch(color, viewMatrix, rrect, stroke));
20473e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    if (!batch) {
20483e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt        return false;
20493e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
20503e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
205199c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt    target->drawBatch(pipelineBuilder, batch);
2052f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    return true;
2053f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org}
20543e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20553e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt///////////////////////////////////////////////////////////////////////////////////////////////////
20563e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20573e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt#ifdef GR_TEST_UTILS
20583e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20593e708c53f79a04b588b6ca8e535e61f986d80b47joshualittBATCH_TEST_DEFINE(CircleBatch) {
20603e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrix(random);
20613e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
20623e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    bool useCoverageAA = random->nextBool();
20636c891107ce0a8431f2327cb8b2f1bfd363cabbbejoshualitt    SkRect circle = GrTest::TestSquare(random);
206421279c7ada1e47e8bfc6375f67768c8eedffb680joshualitt    return create_circle_batch(color, viewMatrix, useCoverageAA, circle,
206521279c7ada1e47e8bfc6375f67768c8eedffb680joshualitt                               GrTest::TestStrokeRec(random));
20663e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
20673e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20683e708c53f79a04b588b6ca8e535e61f986d80b47joshualittBATCH_TEST_DEFINE(EllipseBatch) {
20693e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
20703e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
20716c891107ce0a8431f2327cb8b2f1bfd363cabbbejoshualitt    SkRect ellipse = GrTest::TestSquare(random);
20726c891107ce0a8431f2327cb8b2f1bfd363cabbbejoshualitt    return create_ellipse_batch(color, viewMatrix, true, ellipse,
207321279c7ada1e47e8bfc6375f67768c8eedffb680joshualitt                                GrTest::TestStrokeRec(random));
20743e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
20753e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20763e708c53f79a04b588b6ca8e535e61f986d80b47joshualittBATCH_TEST_DEFINE(DIEllipseBatch) {
20773e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrix(random);
20783e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
20793e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    bool useCoverageAA = random->nextBool();
20806c891107ce0a8431f2327cb8b2f1bfd363cabbbejoshualitt    SkRect ellipse = GrTest::TestSquare(random);
20813e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    return create_diellipse_batch(color, viewMatrix, useCoverageAA, ellipse,
208221279c7ada1e47e8bfc6375f67768c8eedffb680joshualitt                                  GrTest::TestStrokeRec(random));
20833e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
20843e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20853e708c53f79a04b588b6ca8e535e61f986d80b47joshualittBATCH_TEST_DEFINE(RRectBatch) {
20863e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
20873e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
20883e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    const SkRRect& rrect = GrTest::TestRRectSimple(random);
208921279c7ada1e47e8bfc6375f67768c8eedffb680joshualitt    return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(random));
20903e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
20913e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
20923e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt#endif
2093