blob: 5779f8ac4c7dd67b5a7fb511ebd6ab5e335a06a7 [file] [log] [blame]
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrOvalRenderer.h"
9
bsalomon75398562015-08-17 12:55:38 -070010#include "GrBatchFlushState.h"
joshualitt3e708c52015-04-30 13:49:27 -070011#include "GrBatchTest.h"
commit-bot@chromium.org81312832013-03-22 18:34:09 +000012#include "GrDrawTarget.h"
joshualitteb2a6762014-12-04 11:35:33 -080013#include "GrGeometryProcessor.h"
egdaniel605dd0f2014-11-12 08:35:25 -080014#include "GrInvariantOutput.h"
egdaniel8dd688b2015-01-22 10:16:09 -080015#include "GrPipelineBuilder.h"
joshualitt76e7fb62015-02-11 08:52:27 -080016#include "GrProcessor.h"
bsalomoned0bcad2015-05-04 10:36:42 -070017#include "GrResourceProvider.h"
bsalomon72e3ae42015-04-28 08:08:46 -070018#include "GrVertexBuffer.h"
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +000019#include "SkRRect.h"
commit-bot@chromium.org81312832013-03-22 18:34:09 +000020#include "SkStrokeRec.h"
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +000021#include "SkTLazy.h"
joshualitt04194f32016-01-13 10:08:27 -080022#include "batches/GrRectBatchFactory.h"
bsalomon16b99132015-08-13 14:55:50 -070023#include "batches/GrVertexBatch.h"
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +000024#include "effects/GrRRectEffect.h"
egdaniel2d721d32015-11-11 13:06:05 -080025#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniele659a582015-11-13 09:55:43 -080026#include "glsl/GrGLSLGeometryProcessor.h"
egdaniel018fb622015-10-28 07:26:40 -070027#include "glsl/GrGLSLProgramDataManager.h"
egdaniel0eafe792015-11-20 14:01:22 -080028#include "glsl/GrGLSLVarying.h"
egdaniel2d721d32015-11-11 13:06:05 -080029#include "glsl/GrGLSLVertexShaderBuilder.h"
egdaniel7ea439b2015-12-03 09:20:44 -080030#include "glsl/GrGLSLUniformHandler.h"
egdaniel64c47282015-11-13 06:54:19 -080031#include "glsl/GrGLSLUtil.h"
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000032
joshualitt76e7fb62015-02-11 08:52:27 -080033// TODO(joshualitt) - Break this file up during GrBatch post implementation cleanup
34
commit-bot@chromium.org81312832013-03-22 18:34:09 +000035namespace {
brianosmanbb2ff942016-02-11 14:15:18 -080036
commit-bot@chromium.org81312832013-03-22 18:34:09 +000037struct CircleVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000038 SkPoint fPos;
brianosmanbb2ff942016-02-11 14:15:18 -080039 GrColor fColor;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000040 SkPoint fOffset;
commit-bot@chromium.org81312832013-03-22 18:34:09 +000041 SkScalar fOuterRadius;
42 SkScalar fInnerRadius;
43};
44
45struct EllipseVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000046 SkPoint fPos;
brianosmanbb2ff942016-02-11 14:15:18 -080047 GrColor fColor;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000048 SkPoint fOffset;
49 SkPoint fOuterRadii;
50 SkPoint fInnerRadii;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +000051};
52
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +000053struct DIEllipseVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000054 SkPoint fPos;
brianosmanbb2ff942016-02-11 14:15:18 -080055 GrColor fColor;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000056 SkPoint fOuterOffset;
57 SkPoint fInnerOffset;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +000058};
59
commit-bot@chromium.org81312832013-03-22 18:34:09 +000060inline bool circle_stays_circle(const SkMatrix& m) {
61 return m.isSimilarity();
62}
63
64}
65
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000066///////////////////////////////////////////////////////////////////////////////
67
68/**
bsalomonce1c8862014-12-15 07:11:22 -080069 * The output of this effect is a modulation of the input color and coverage for a circle. It
70 * operates in a space normalized by the circle radius (outer radius in the case of a stroke)
71 * with origin at the circle center. Two vertex attributes are used:
72 * vec2f : position in device space of the bounding geometry vertices
73 * vec4f : (p.xy, outerRad, innerRad)
74 * p is the position in the normalized space.
75 * outerRad is the outerRadius in device space.
76 * innerRad is the innerRadius in normalized space (ignored if not stroking).
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000077 */
78
joshualitt249af152014-09-15 11:41:13 -070079class CircleEdgeEffect : public GrGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000080public:
joshualittb8c241a2015-05-19 08:23:30 -070081 static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix,
82 bool usesLocalCoords) {
halcanary385fe4d2015-08-26 13:07:48 -070083 return new CircleEdgeEffect(color, stroke, localMatrix, usesLocalCoords);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000084 }
85
joshualitt71c92602015-01-14 08:12:47 -080086 const Attribute* inPosition() const { return fInPosition; }
brianosmanbb2ff942016-02-11 14:15:18 -080087 const Attribute* inColor() const { return fInColor; }
joshualitt71c92602015-01-14 08:12:47 -080088 const Attribute* inCircleEdge() const { return fInCircleEdge; }
joshualitt88c23fc2015-05-13 14:18:07 -070089 GrColor color() const { return fColor; }
joshualittb8c241a2015-05-19 08:23:30 -070090 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
joshualitte3ababe2015-05-15 07:56:07 -070091 const SkMatrix& localMatrix() const { return fLocalMatrix; }
joshualittb8c241a2015-05-19 08:23:30 -070092 bool usesLocalCoords() const { return fUsesLocalCoords; }
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000093 virtual ~CircleEdgeEffect() {}
94
mtklein36352bf2015-03-25 18:17:31 -070095 const char* name() const override { return "CircleEdge"; }
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000096
97 inline bool isStroked() const { return fStroke; }
98
egdaniel57d3b032015-11-13 11:57:27 -080099 class GLSLProcessor : public GrGLSLGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000100 public:
brianosmanbb2ff942016-02-11 14:15:18 -0800101 GLSLProcessor() {}
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000102
mtklein36352bf2015-03-25 18:17:31 -0700103 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
joshualitt2dd1ae02014-12-03 06:24:10 -0800104 const CircleEdgeEffect& ce = args.fGP.cast<CircleEdgeEffect>();
egdaniel4ca2e602015-11-18 08:01:26 -0800105 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -0800106 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -0800107 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
joshualitt2dd1ae02014-12-03 06:24:10 -0800108
joshualittabb52a12015-01-13 15:02:10 -0800109 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -0800110 varyingHandler->emitAttributes(ce);
joshualittabb52a12015-01-13 15:02:10 -0800111
egdaniel8dcdedc2015-11-11 06:27:20 -0800112 GrGLSLVertToFrag v(kVec4f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800113 varyingHandler->addVarying("CircleEdge", &v);
egdaniel4ca2e602015-11-18 08:01:26 -0800114 vertBuilder->codeAppendf("%s = %s;", v.vsOut(), ce.inCircleEdge()->fName);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000115
egdaniel4ca2e602015-11-18 08:01:26 -0800116 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualittb8c241a2015-05-19 08:23:30 -0700117 // setup pass through color
118 if (!ce.colorIgnored()) {
brianosmanbb2ff942016-02-11 14:15:18 -0800119 varyingHandler->addPassThroughAttribute(ce.inColor(), args.fOutputColor);
joshualittb8c241a2015-05-19 08:23:30 -0700120 }
joshualitt9b989322014-12-15 14:16:27 -0800121
joshualittabb52a12015-01-13 15:02:10 -0800122 // Setup position
egdaniel7ea439b2015-12-03 09:20:44 -0800123 this->setupPosition(vertBuilder, gpArgs, ce.inPosition()->fName);
joshualittabb52a12015-01-13 15:02:10 -0800124
125 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -0800126 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -0800127 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -0800128 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800129 gpArgs->fPositionVar,
130 ce.inPosition()->fName,
131 ce.localMatrix(),
132 args.fTransformsIn,
133 args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800134
egdaniel4ca2e602015-11-18 08:01:26 -0800135 fragBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn());
136 fragBuilder->codeAppendf("float edgeAlpha = clamp(%s.z * (1.0 - d), 0.0, 1.0);",
137 v.fsIn());
joshualitt2dd1ae02014-12-03 06:24:10 -0800138 if (ce.isStroked()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800139 fragBuilder->codeAppendf("float innerAlpha = clamp(%s.z * (d - %s.w), 0.0, 1.0);",
140 v.fsIn(), v.fsIn());
141 fragBuilder->codeAppend("edgeAlpha *= innerAlpha;");
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000142 }
commit-bot@chromium.org0a6cb602013-04-11 15:05:37 +0000143
egdaniel4ca2e602015-11-18 08:01:26 -0800144 fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000145 }
146
robertphillips46d36f02015-01-18 08:14:14 -0800147 static void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700148 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700149 GrProcessorKeyBuilder* b) {
joshualitte3ababe2015-05-15 07:56:07 -0700150 const CircleEdgeEffect& ce = gp.cast<CircleEdgeEffect>();
151 uint16_t key = ce.isStroked() ? 0x1 : 0x0;
joshualittb8c241a2015-05-19 08:23:30 -0700152 key |= ce.usesLocalCoords() && ce.localMatrix().hasPerspective() ? 0x2 : 0x0;
153 key |= ce.colorIgnored() ? 0x4 : 0x0;
154 b->add32(key);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000155 }
156
egdaniel018fb622015-10-28 07:26:40 -0700157 void setData(const GrGLSLProgramDataManager& pdman,
158 const GrPrimitiveProcessor& gp) override {
joshualitt9b989322014-12-15 14:16:27 -0800159 }
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000160
joshualitte3ababe2015-05-15 07:56:07 -0700161 void setTransformData(const GrPrimitiveProcessor& primProc,
egdaniel018fb622015-10-28 07:26:40 -0700162 const GrGLSLProgramDataManager& pdman,
joshualitte3ababe2015-05-15 07:56:07 -0700163 int index,
164 const SkTArray<const GrCoordTransform*, true>& transforms) override {
165 this->setTransformDataHelper<CircleEdgeEffect>(primProc, pdman, index, transforms);
166 }
167
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000168 private:
egdaniele659a582015-11-13 09:55:43 -0800169 typedef GrGLSLGeometryProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000170 };
171
egdaniel57d3b032015-11-13 11:57:27 -0800172 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
173 GLSLProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800174 }
175
egdaniel57d3b032015-11-13 11:57:27 -0800176 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
177 return new GLSLProcessor();
joshualitteb2a6762014-12-04 11:35:33 -0800178 }
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000179
180private:
joshualittb8c241a2015-05-19 08:23:30 -0700181 CircleEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix, bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700182 : fColor(color)
joshualittb8c241a2015-05-19 08:23:30 -0700183 , fLocalMatrix(localMatrix)
184 , fUsesLocalCoords(usesLocalCoords) {
joshualitteb2a6762014-12-04 11:35:33 -0800185 this->initClassID<CircleEdgeEffect>();
senorblancof2539d52015-05-20 14:03:42 -0700186 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
187 kHigh_GrSLPrecision));
brianosmanbb2ff942016-02-11 14:15:18 -0800188 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800189 fInCircleEdge = &this->addVertexAttrib(Attribute("inCircleEdge",
joshualitt2dd1ae02014-12-03 06:24:10 -0800190 kVec4f_GrVertexAttribType));
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000191 fStroke = stroke;
192 }
193
joshualitt88c23fc2015-05-13 14:18:07 -0700194 GrColor fColor;
joshualitte3ababe2015-05-15 07:56:07 -0700195 SkMatrix fLocalMatrix;
joshualitt71c92602015-01-14 08:12:47 -0800196 const Attribute* fInPosition;
brianosmanbb2ff942016-02-11 14:15:18 -0800197 const Attribute* fInColor;
joshualitt71c92602015-01-14 08:12:47 -0800198 const Attribute* fInCircleEdge;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000199 bool fStroke;
joshualittb8c241a2015-05-19 08:23:30 -0700200 bool fUsesLocalCoords;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000201
joshualittb0a8a372014-09-23 09:50:21 -0700202 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000203
joshualitt249af152014-09-15 11:41:13 -0700204 typedef GrGeometryProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000205};
206
joshualittb0a8a372014-09-23 09:50:21 -0700207GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleEdgeEffect);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000208
bsalomonc21b09e2015-08-28 18:46:56 -0700209const GrGeometryProcessor* CircleEdgeEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700210 return CircleEdgeEffect::Create(GrRandomColor(d->fRandom),
211 d->fRandom->nextBool(),
212 GrTest::TestMatrix(d->fRandom),
213 d->fRandom->nextBool());
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000214}
215
216///////////////////////////////////////////////////////////////////////////////
217
218/**
219 * The output of this effect is a modulation of the input color and coverage for an axis-aligned
skia.committer@gmail.com8be02fc2013-05-17 07:01:11 +0000220 * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii,
221 * in both x and y directions.
222 *
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +0000223 * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000224 */
225
joshualitt249af152014-09-15 11:41:13 -0700226class EllipseEdgeEffect : public GrGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000227public:
joshualittb8c241a2015-05-19 08:23:30 -0700228 static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix,
229 bool usesLocalCoords) {
halcanary385fe4d2015-08-26 13:07:48 -0700230 return new EllipseEdgeEffect(color, stroke, localMatrix, usesLocalCoords);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000231 }
232
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000233 virtual ~EllipseEdgeEffect() {}
234
mtklein36352bf2015-03-25 18:17:31 -0700235 const char* name() const override { return "EllipseEdge"; }
joshualitt2dd1ae02014-12-03 06:24:10 -0800236
joshualitt71c92602015-01-14 08:12:47 -0800237 const Attribute* inPosition() const { return fInPosition; }
brianosmanbb2ff942016-02-11 14:15:18 -0800238 const Attribute* inColor() const { return fInColor; }
joshualitt71c92602015-01-14 08:12:47 -0800239 const Attribute* inEllipseOffset() const { return fInEllipseOffset; }
240 const Attribute* inEllipseRadii() const { return fInEllipseRadii; }
joshualitt88c23fc2015-05-13 14:18:07 -0700241 GrColor color() const { return fColor; }
joshualittb8c241a2015-05-19 08:23:30 -0700242 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
joshualitte3ababe2015-05-15 07:56:07 -0700243 const SkMatrix& localMatrix() const { return fLocalMatrix; }
joshualittb8c241a2015-05-19 08:23:30 -0700244 bool usesLocalCoords() const { return fUsesLocalCoords; }
joshualitt249af152014-09-15 11:41:13 -0700245
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000246 inline bool isStroked() const { return fStroke; }
247
egdaniel57d3b032015-11-13 11:57:27 -0800248 class GLSLProcessor : public GrGLSLGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000249 public:
brianosmanbb2ff942016-02-11 14:15:18 -0800250 GLSLProcessor() {}
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000251
mtklein36352bf2015-03-25 18:17:31 -0700252 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
joshualitt2dd1ae02014-12-03 06:24:10 -0800253 const EllipseEdgeEffect& ee = args.fGP.cast<EllipseEdgeEffect>();
egdaniel4ca2e602015-11-18 08:01:26 -0800254 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -0800255 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -0800256 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000257
joshualittabb52a12015-01-13 15:02:10 -0800258 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -0800259 varyingHandler->emitAttributes(ee);
joshualittabb52a12015-01-13 15:02:10 -0800260
egdaniel8dcdedc2015-11-11 06:27:20 -0800261 GrGLSLVertToFrag ellipseOffsets(kVec2f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800262 varyingHandler->addVarying("EllipseOffsets", &ellipseOffsets);
egdaniel4ca2e602015-11-18 08:01:26 -0800263 vertBuilder->codeAppendf("%s = %s;", ellipseOffsets.vsOut(),
joshualitt2dd1ae02014-12-03 06:24:10 -0800264 ee.inEllipseOffset()->fName);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000265
egdaniel8dcdedc2015-11-11 06:27:20 -0800266 GrGLSLVertToFrag ellipseRadii(kVec4f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800267 varyingHandler->addVarying("EllipseRadii", &ellipseRadii);
egdaniel4ca2e602015-11-18 08:01:26 -0800268 vertBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(),
joshualitt2dd1ae02014-12-03 06:24:10 -0800269 ee.inEllipseRadii()->fName);
270
egdaniel4ca2e602015-11-18 08:01:26 -0800271 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualittb8c241a2015-05-19 08:23:30 -0700272 // setup pass through color
273 if (!ee.colorIgnored()) {
brianosmanbb2ff942016-02-11 14:15:18 -0800274 varyingHandler->addPassThroughAttribute(ee.inColor(), args.fOutputColor);
joshualittb8c241a2015-05-19 08:23:30 -0700275 }
joshualitt9b989322014-12-15 14:16:27 -0800276
joshualittabb52a12015-01-13 15:02:10 -0800277 // Setup position
egdaniel7ea439b2015-12-03 09:20:44 -0800278 this->setupPosition(vertBuilder, gpArgs, ee.inPosition()->fName);
joshualittabb52a12015-01-13 15:02:10 -0800279
280 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -0800281 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -0800282 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -0800283 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800284 gpArgs->fPositionVar,
285 ee.inPosition()->fName,
286 ee.localMatrix(),
287 args.fTransformsIn,
288 args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800289
skia.committer@gmail.com8be02fc2013-05-17 07:01:11 +0000290 // for outer curve
egdaniel4ca2e602015-11-18 08:01:26 -0800291 fragBuilder->codeAppendf("vec2 scaledOffset = %s*%s.xy;", ellipseOffsets.fsIn(),
292 ellipseRadii.fsIn());
293 fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
294 fragBuilder->codeAppendf("vec2 grad = 2.0*scaledOffset*%s.xy;", ellipseRadii.fsIn());
295 fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
joshualitt74077b92014-10-24 11:26:03 -0700296
commit-bot@chromium.org1b035d82014-04-09 17:11:09 +0000297 // avoid calling inversesqrt on zero.
egdaniel4ca2e602015-11-18 08:01:26 -0800298 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
299 fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
brianosmanc6052ac2016-02-12 10:20:00 -0800300 fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000301
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +0000302 // for inner curve
joshualitt2dd1ae02014-12-03 06:24:10 -0800303 if (ee.isStroked()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800304 fragBuilder->codeAppendf("scaledOffset = %s*%s.zw;",
305 ellipseOffsets.fsIn(), ellipseRadii.fsIn());
306 fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
307 fragBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;",
308 ellipseRadii.fsIn());
309 fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
310 fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000311 }
312
egdaniel4ca2e602015-11-18 08:01:26 -0800313 fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000314 }
315
robertphillips46d36f02015-01-18 08:14:14 -0800316 static void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700317 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700318 GrProcessorKeyBuilder* b) {
joshualitte3ababe2015-05-15 07:56:07 -0700319 const EllipseEdgeEffect& ee = gp.cast<EllipseEdgeEffect>();
320 uint16_t key = ee.isStroked() ? 0x1 : 0x0;
joshualittb8c241a2015-05-19 08:23:30 -0700321 key |= ee.usesLocalCoords() && ee.localMatrix().hasPerspective() ? 0x2 : 0x0;
322 key |= ee.colorIgnored() ? 0x4 : 0x0;
323 b->add32(key);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000324 }
325
egdaniel018fb622015-10-28 07:26:40 -0700326 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp) override {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000327 }
328
joshualitte3ababe2015-05-15 07:56:07 -0700329 void setTransformData(const GrPrimitiveProcessor& primProc,
egdaniel018fb622015-10-28 07:26:40 -0700330 const GrGLSLProgramDataManager& pdman,
joshualitte3ababe2015-05-15 07:56:07 -0700331 int index,
332 const SkTArray<const GrCoordTransform*, true>& transforms) override {
333 this->setTransformDataHelper<EllipseEdgeEffect>(primProc, pdman, index, transforms);
334 }
335
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000336 private:
egdaniele659a582015-11-13 09:55:43 -0800337 typedef GrGLSLGeometryProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000338 };
339
egdaniel57d3b032015-11-13 11:57:27 -0800340 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
341 GLSLProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800342 }
343
egdaniel57d3b032015-11-13 11:57:27 -0800344 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
345 return new GLSLProcessor();
joshualitteb2a6762014-12-04 11:35:33 -0800346 }
347
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000348private:
joshualittb8c241a2015-05-19 08:23:30 -0700349 EllipseEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix,
350 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700351 : fColor(color)
joshualittb8c241a2015-05-19 08:23:30 -0700352 , fLocalMatrix(localMatrix)
353 , fUsesLocalCoords(usesLocalCoords) {
joshualitteb2a6762014-12-04 11:35:33 -0800354 this->initClassID<EllipseEdgeEffect>();
joshualitt71c92602015-01-14 08:12:47 -0800355 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
brianosmanbb2ff942016-02-11 14:15:18 -0800356 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800357 fInEllipseOffset = &this->addVertexAttrib(Attribute("inEllipseOffset",
joshualitt465283c2015-09-11 08:19:35 -0700358 kVec2f_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800359 fInEllipseRadii = &this->addVertexAttrib(Attribute("inEllipseRadii",
joshualitt465283c2015-09-11 08:19:35 -0700360 kVec4f_GrVertexAttribType));
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000361 fStroke = stroke;
362 }
363
joshualitt71c92602015-01-14 08:12:47 -0800364 const Attribute* fInPosition;
brianosmanbb2ff942016-02-11 14:15:18 -0800365 const Attribute* fInColor;
joshualitt71c92602015-01-14 08:12:47 -0800366 const Attribute* fInEllipseOffset;
367 const Attribute* fInEllipseRadii;
joshualitt88c23fc2015-05-13 14:18:07 -0700368 GrColor fColor;
joshualitte3ababe2015-05-15 07:56:07 -0700369 SkMatrix fLocalMatrix;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000370 bool fStroke;
joshualittb8c241a2015-05-19 08:23:30 -0700371 bool fUsesLocalCoords;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000372
joshualittb0a8a372014-09-23 09:50:21 -0700373 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000374
joshualitt249af152014-09-15 11:41:13 -0700375 typedef GrGeometryProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000376};
377
joshualittb0a8a372014-09-23 09:50:21 -0700378GR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseEdgeEffect);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000379
bsalomonc21b09e2015-08-28 18:46:56 -0700380const GrGeometryProcessor* EllipseEdgeEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700381 return EllipseEdgeEffect::Create(GrRandomColor(d->fRandom),
382 d->fRandom->nextBool(),
383 GrTest::TestMatrix(d->fRandom),
384 d->fRandom->nextBool());
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000385}
386
387///////////////////////////////////////////////////////////////////////////////
388
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000389/**
skia.committer@gmail.com6fc1b492013-09-06 07:01:45 +0000390 * The output of this effect is a modulation of the input color and coverage for an ellipse,
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000391 * specified as a 2D offset from center for both the outer and inner paths (if stroked). The
392 * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge corrected by
393 * using differentials.
394 *
395 * The result is device-independent and can be used with any affine matrix.
396 */
397
joshualitt249af152014-09-15 11:41:13 -0700398class DIEllipseEdgeEffect : public GrGeometryProcessor {
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000399public:
400 enum Mode { kStroke = 0, kHairline, kFill };
401
joshualittb8c241a2015-05-19 08:23:30 -0700402 static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, Mode mode,
403 bool usesLocalCoords) {
halcanary385fe4d2015-08-26 13:07:48 -0700404 return new DIEllipseEdgeEffect(color, viewMatrix, mode, usesLocalCoords);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000405 }
406
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000407 virtual ~DIEllipseEdgeEffect() {}
408
mtklein36352bf2015-03-25 18:17:31 -0700409 const char* name() const override { return "DIEllipseEdge"; }
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000410
joshualitt71c92602015-01-14 08:12:47 -0800411 const Attribute* inPosition() const { return fInPosition; }
brianosmanbb2ff942016-02-11 14:15:18 -0800412 const Attribute* inColor() const { return fInColor; }
joshualitt71c92602015-01-14 08:12:47 -0800413 const Attribute* inEllipseOffsets0() const { return fInEllipseOffsets0; }
414 const Attribute* inEllipseOffsets1() const { return fInEllipseOffsets1; }
joshualitt88c23fc2015-05-13 14:18:07 -0700415 GrColor color() const { return fColor; }
joshualittb8c241a2015-05-19 08:23:30 -0700416 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
joshualitte578a952015-05-14 10:09:13 -0700417 const SkMatrix& viewMatrix() const { return fViewMatrix; }
joshualittb8c241a2015-05-19 08:23:30 -0700418 bool usesLocalCoords() const { return fUsesLocalCoords; }
joshualitt249af152014-09-15 11:41:13 -0700419
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000420 inline Mode getMode() const { return fMode; }
421
egdaniel57d3b032015-11-13 11:57:27 -0800422 class GLSLProcessor : public GrGLSLGeometryProcessor {
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000423 public:
egdaniel57d3b032015-11-13 11:57:27 -0800424 GLSLProcessor()
brianosmanbb2ff942016-02-11 14:15:18 -0800425 : fViewMatrix(SkMatrix::InvalidMatrix()) {}
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000426
joshualitt465283c2015-09-11 08:19:35 -0700427 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
joshualitt2dd1ae02014-12-03 06:24:10 -0800428 const DIEllipseEdgeEffect& ee = args.fGP.cast<DIEllipseEdgeEffect>();
egdaniel4ca2e602015-11-18 08:01:26 -0800429 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -0800430 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -0800431 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000432
joshualittabb52a12015-01-13 15:02:10 -0800433 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -0800434 varyingHandler->emitAttributes(ee);
joshualittabb52a12015-01-13 15:02:10 -0800435
egdaniel8dcdedc2015-11-11 06:27:20 -0800436 GrGLSLVertToFrag offsets0(kVec2f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800437 varyingHandler->addVarying("EllipseOffsets0", &offsets0);
egdaniel4ca2e602015-11-18 08:01:26 -0800438 vertBuilder->codeAppendf("%s = %s;", offsets0.vsOut(),
joshualitt2dd1ae02014-12-03 06:24:10 -0800439 ee.inEllipseOffsets0()->fName);
joshualitt74077b92014-10-24 11:26:03 -0700440
egdaniel8dcdedc2015-11-11 06:27:20 -0800441 GrGLSLVertToFrag offsets1(kVec2f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800442 varyingHandler->addVarying("EllipseOffsets1", &offsets1);
egdaniel4ca2e602015-11-18 08:01:26 -0800443 vertBuilder->codeAppendf("%s = %s;", offsets1.vsOut(),
joshualitt2dd1ae02014-12-03 06:24:10 -0800444 ee.inEllipseOffsets1()->fName);
445
egdaniel4ca2e602015-11-18 08:01:26 -0800446 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualittb8c241a2015-05-19 08:23:30 -0700447 // setup pass through color
448 if (!ee.colorIgnored()) {
brianosmanbb2ff942016-02-11 14:15:18 -0800449 varyingHandler->addPassThroughAttribute(ee.inColor(), args.fOutputColor);
joshualittb8c241a2015-05-19 08:23:30 -0700450 }
joshualitt9b989322014-12-15 14:16:27 -0800451
joshualittabb52a12015-01-13 15:02:10 -0800452 // Setup position
egdaniel7ea439b2015-12-03 09:20:44 -0800453 this->setupPosition(vertBuilder,
454 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800455 gpArgs,
456 ee.inPosition()->fName,
457 ee.viewMatrix(),
joshualitt5559ca22015-05-21 15:50:36 -0700458 &fViewMatrixUniform);
joshualittabb52a12015-01-13 15:02:10 -0800459
460 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -0800461 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -0800462 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -0800463 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800464 gpArgs->fPositionVar,
465 ee.inPosition()->fName,
466 args.fTransformsIn,
467 args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800468
egdaniel4ca2e602015-11-18 08:01:26 -0800469 SkAssertResult(fragBuilder->enableFeature(
egdaniel2d721d32015-11-11 13:06:05 -0800470 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000471 // for outer curve
egdaniel4ca2e602015-11-18 08:01:26 -0800472 fragBuilder->codeAppendf("vec2 scaledOffset = %s.xy;", offsets0.fsIn());
473 fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
474 fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s);", offsets0.fsIn());
475 fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s);", offsets0.fsIn());
476 fragBuilder->codeAppendf("vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
477 " 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
478 offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn());
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000479
egdaniel4ca2e602015-11-18 08:01:26 -0800480 fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
commit-bot@chromium.org1b035d82014-04-09 17:11:09 +0000481 // avoid calling inversesqrt on zero.
egdaniel4ca2e602015-11-18 08:01:26 -0800482 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
483 fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
joshualitt2dd1ae02014-12-03 06:24:10 -0800484 if (kHairline == ee.getMode()) {
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000485 // can probably do this with one step
egdaniel4ca2e602015-11-18 08:01:26 -0800486 fragBuilder->codeAppend("float edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);");
487 fragBuilder->codeAppend("edgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);");
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000488 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800489 fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000490 }
491
492 // for inner curve
joshualitt2dd1ae02014-12-03 06:24:10 -0800493 if (kStroke == ee.getMode()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800494 fragBuilder->codeAppendf("scaledOffset = %s.xy;", offsets1.fsIn());
495 fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
496 fragBuilder->codeAppendf("duvdx = dFdx(%s);", offsets1.fsIn());
497 fragBuilder->codeAppendf("duvdy = dFdy(%s);", offsets1.fsIn());
498 fragBuilder->codeAppendf("grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
499 " 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
500 offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(),
501 offsets1.fsIn());
502 fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
503 fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000504 }
505
egdaniel4ca2e602015-11-18 08:01:26 -0800506 fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000507 }
508
robertphillips46d36f02015-01-18 08:14:14 -0800509 static void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700510 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700511 GrProcessorKeyBuilder* b) {
robertphillips46d36f02015-01-18 08:14:14 -0800512 const DIEllipseEdgeEffect& ellipseEffect = gp.cast<DIEllipseEdgeEffect>();
joshualitt8fc6c2d2014-12-22 15:27:05 -0800513 uint16_t key = ellipseEffect.getMode();
joshualittb8c241a2015-05-19 08:23:30 -0700514 key |= ellipseEffect.colorIgnored() << 9;
515 key |= ComputePosKey(ellipseEffect.viewMatrix()) << 10;
516 b->add32(key);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000517 }
518
egdaniel018fb622015-10-28 07:26:40 -0700519 void setData(const GrGLSLProgramDataManager& pdman,
520 const GrPrimitiveProcessor& gp) override {
joshualitte578a952015-05-14 10:09:13 -0700521 const DIEllipseEdgeEffect& dee = gp.cast<DIEllipseEdgeEffect>();
joshualitt5559ca22015-05-21 15:50:36 -0700522
523 if (!dee.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dee.viewMatrix())) {
524 fViewMatrix = dee.viewMatrix();
egdaniel018fb622015-10-28 07:26:40 -0700525 float viewMatrix[3 * 3];
egdaniel64c47282015-11-13 06:54:19 -0800526 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
joshualitt5559ca22015-05-21 15:50:36 -0700527 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
528 }
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000529 }
530
531 private:
joshualitt5559ca22015-05-21 15:50:36 -0700532 SkMatrix fViewMatrix;
joshualitt5559ca22015-05-21 15:50:36 -0700533 UniformHandle fViewMatrixUniform;
joshualitt9b989322014-12-15 14:16:27 -0800534
egdaniele659a582015-11-13 09:55:43 -0800535 typedef GrGLSLGeometryProcessor INHERITED;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000536 };
537
egdaniel57d3b032015-11-13 11:57:27 -0800538 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
539 GLSLProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800540 }
541
egdaniel57d3b032015-11-13 11:57:27 -0800542 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
543 return new GLSLProcessor();
joshualitteb2a6762014-12-04 11:35:33 -0800544 }
545
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000546private:
joshualittb8c241a2015-05-19 08:23:30 -0700547 DIEllipseEdgeEffect(GrColor color, const SkMatrix& viewMatrix, Mode mode,
548 bool usesLocalCoords)
joshualitte578a952015-05-14 10:09:13 -0700549 : fColor(color)
joshualittb8c241a2015-05-19 08:23:30 -0700550 , fViewMatrix(viewMatrix)
551 , fUsesLocalCoords(usesLocalCoords) {
joshualitteb2a6762014-12-04 11:35:33 -0800552 this->initClassID<DIEllipseEdgeEffect>();
senorblancof2539d52015-05-20 14:03:42 -0700553 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
554 kHigh_GrSLPrecision));
brianosmanbb2ff942016-02-11 14:15:18 -0800555 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800556 fInEllipseOffsets0 = &this->addVertexAttrib(Attribute("inEllipseOffsets0",
joshualittb8c241a2015-05-19 08:23:30 -0700557 kVec2f_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800558 fInEllipseOffsets1 = &this->addVertexAttrib(Attribute("inEllipseOffsets1",
joshualittb8c241a2015-05-19 08:23:30 -0700559 kVec2f_GrVertexAttribType));
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000560 fMode = mode;
561 }
562
joshualitt71c92602015-01-14 08:12:47 -0800563 const Attribute* fInPosition;
brianosmanbb2ff942016-02-11 14:15:18 -0800564 const Attribute* fInColor;
joshualitt71c92602015-01-14 08:12:47 -0800565 const Attribute* fInEllipseOffsets0;
566 const Attribute* fInEllipseOffsets1;
joshualitt88c23fc2015-05-13 14:18:07 -0700567 GrColor fColor;
joshualitte578a952015-05-14 10:09:13 -0700568 SkMatrix fViewMatrix;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000569 Mode fMode;
joshualittb8c241a2015-05-19 08:23:30 -0700570 bool fUsesLocalCoords;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000571
joshualittb0a8a372014-09-23 09:50:21 -0700572 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000573
joshualitt249af152014-09-15 11:41:13 -0700574 typedef GrGeometryProcessor INHERITED;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000575};
576
joshualittb0a8a372014-09-23 09:50:21 -0700577GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseEdgeEffect);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000578
bsalomonc21b09e2015-08-28 18:46:56 -0700579const GrGeometryProcessor* DIEllipseEdgeEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700580 return DIEllipseEdgeEffect::Create(GrRandomColor(d->fRandom),
581 GrTest::TestMatrix(d->fRandom),
582 (Mode)(d->fRandom->nextRangeU(0,2)),
583 d->fRandom->nextBool());
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000584}
585
586///////////////////////////////////////////////////////////////////////////////
587
robertphillipsea461502015-05-26 11:38:03 -0700588bool GrOvalRenderer::DrawOval(GrDrawTarget* target,
joshualittae3d63a2015-07-13 08:44:06 -0700589 const GrPipelineBuilder& pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800590 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800591 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800592 bool useAA,
593 const SkRect& oval,
joshualittae3d63a2015-07-13 08:44:06 -0700594 const SkStrokeRec& stroke) {
595 bool useCoverageAA = useAA && !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000596
597 if (!useCoverageAA) {
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000598 return false;
599 }
600
skia.committer@gmail.com7e328512013-03-23 07:01:28 +0000601 // we can draw circles
joshualitt8059eb92014-12-29 15:10:07 -0800602 if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(viewMatrix)) {
robertphillipsea461502015-05-26 11:38:03 -0700603 DrawCircle(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval, stroke);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000604 // if we have shader derivative support, render as device-independent
jvanverthe9c0fc62015-04-29 11:18:05 -0700605 } else if (target->caps()->shaderCaps()->shaderDerivativeSupport()) {
robertphillipsea461502015-05-26 11:38:03 -0700606 return DrawDIEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
607 stroke);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000608 // otherwise axis-aligned ellipses only
joshualitt8059eb92014-12-29 15:10:07 -0800609 } else if (viewMatrix.rectStaysRect()) {
robertphillipsea461502015-05-26 11:38:03 -0700610 return DrawEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
611 stroke);
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000612 } else {
613 return false;
614 }
615
616 return true;
617}
618
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +0000619///////////////////////////////////////////////////////////////////////////////
620
bsalomonabd30f52015-08-13 13:34:48 -0700621class CircleBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -0800622public:
reed1b55a962015-09-17 20:16:13 -0700623 DEFINE_BATCH_CLASS_ID
624
joshualitt76e7fb62015-02-11 08:52:27 -0800625 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -0800626 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -0700627 SkRect fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -0800628 SkScalar fInnerRadius;
629 SkScalar fOuterRadius;
reed1b55a962015-09-17 20:16:13 -0700630 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -0800631 bool fStroke;
joshualitt76e7fb62015-02-11 08:52:27 -0800632 };
633
halcanary385fe4d2015-08-26 13:07:48 -0700634 static GrDrawBatch* Create(const Geometry& geometry) { return new CircleBatch(geometry); }
joshualitt76e7fb62015-02-11 08:52:27 -0800635
mtklein36352bf2015-03-25 18:17:31 -0700636 const char* name() const override { return "CircleBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -0800637
robertphillipse004bfc2015-11-16 09:06:59 -0800638 SkString dumpInfo() const override {
639 SkString string;
640 for (int i = 0; i < fGeoData.count(); ++i) {
641 string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
642 "InnerRad: %.2f, OuterRad: %.2f\n",
643 fGeoData[i].fColor,
644 fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
645 fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
646 fGeoData[i].fInnerRadius,
647 fGeoData[i].fOuterRadius);
648 }
649 string.append(INHERITED::dumpInfo());
650 return string;
651 }
652
ethannicholasff210322015-11-24 12:10:10 -0800653 void computePipelineOptimizations(GrInitInvariantOutput* color,
654 GrInitInvariantOutput* coverage,
655 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -0800656 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -0800657 color->setKnownFourComponents(fGeoData[0].fColor);
658 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -0800659 }
660
bsalomone46f9fe2015-08-18 06:05:14 -0700661private:
ethannicholasff210322015-11-24 12:10:10 -0800662 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -0800663 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -0800664 if (!overrides.readsColor()) {
joshualitt76e7fb62015-02-11 08:52:27 -0800665 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -0800666 }
ethannicholasff210322015-11-24 12:10:10 -0800667 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -0800668
669 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -0800670 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -0800671 fBatch.fColor = fGeoData[0].fColor;
672 fBatch.fStroke = fGeoData[0].fStroke;
ethannicholasff210322015-11-24 12:10:10 -0800673 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
674 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -0800675 }
676
joshualitt144c3c82015-11-30 12:30:13 -0800677 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -0800678 SkMatrix invert;
679 if (!this->viewMatrix().invert(&invert)) {
680 return;
681 }
682
683 // Setup geometry processor
684 SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
685 this->stroke(),
joshualittb8c241a2015-05-19 08:23:30 -0700686 invert,
687 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -0800688
bsalomon75398562015-08-17 12:55:38 -0700689 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -0800690
joshualitt76e7fb62015-02-11 08:52:27 -0800691 int instanceCount = fGeoData.count();
joshualitt76e7fb62015-02-11 08:52:27 -0800692 size_t vertexStride = gp->getVertexStride();
693 SkASSERT(vertexStride == sizeof(CircleVertex));
bsalomonb5238a72015-05-05 07:49:49 -0700694 QuadHelper helper;
bsalomon75398562015-08-17 12:55:38 -0700695 CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target, vertexStride,
bsalomonb5238a72015-05-05 07:49:49 -0700696 instanceCount));
697 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800698 return;
699 }
700
joshualitt76e7fb62015-02-11 08:52:27 -0800701 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800702 const Geometry& geom = fGeoData[i];
joshualitt76e7fb62015-02-11 08:52:27 -0800703
brianosmanbb2ff942016-02-11 14:15:18 -0800704 GrColor color = geom.fColor;
bsalomonb5238a72015-05-05 07:49:49 -0700705 SkScalar innerRadius = geom.fInnerRadius;
706 SkScalar outerRadius = geom.fOuterRadius;
joshualitt76e7fb62015-02-11 08:52:27 -0800707
bsalomonb5238a72015-05-05 07:49:49 -0700708 const SkRect& bounds = geom.fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -0800709
710 // The inner radius in the vertex data must be specified in normalized space.
711 innerRadius = innerRadius / outerRadius;
712 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -0800713 verts[0].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800714 verts[0].fOffset = SkPoint::Make(-1, -1);
715 verts[0].fOuterRadius = outerRadius;
716 verts[0].fInnerRadius = innerRadius;
717
718 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -0800719 verts[1].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800720 verts[1].fOffset = SkPoint::Make(-1, 1);
721 verts[1].fOuterRadius = outerRadius;
722 verts[1].fInnerRadius = innerRadius;
723
724 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -0800725 verts[2].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800726 verts[2].fOffset = SkPoint::Make(1, 1);
727 verts[2].fOuterRadius = outerRadius;
728 verts[2].fInnerRadius = innerRadius;
729
730 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -0800731 verts[3].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800732 verts[3].fOffset = SkPoint::Make(1, -1);
733 verts[3].fOuterRadius = outerRadius;
734 verts[3].fInnerRadius = innerRadius;
735
bsalomonb5238a72015-05-05 07:49:49 -0700736 verts += kVerticesPerQuad;
joshualitt76e7fb62015-02-11 08:52:27 -0800737 }
bsalomon75398562015-08-17 12:55:38 -0700738 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -0800739 }
740
741 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
742
reed1b55a962015-09-17 20:16:13 -0700743 CircleBatch(const Geometry& geometry) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -0800744 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -0700745
746 this->setBounds(geometry.fDevBounds);
joshualitt76e7fb62015-02-11 08:52:27 -0800747 }
748
bsalomoncb02b382015-08-12 11:14:50 -0700749 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -0700750 CircleBatch* that = t->cast<CircleBatch>();
751 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
752 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -0700753 return false;
754 }
755
joshualitt76e7fb62015-02-11 08:52:27 -0800756 if (this->stroke() != that->stroke()) {
757 return false;
758 }
759
760 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
761 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
762 return false;
763 }
764
765 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -0700766 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -0800767 return true;
768 }
769
770 GrColor color() const { return fBatch.fColor; }
771 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
772 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
773 bool stroke() const { return fBatch.fStroke; }
774
775 struct BatchTracker {
776 GrColor fColor;
777 bool fStroke;
778 bool fUsesLocalCoords;
779 bool fColorIgnored;
780 bool fCoverageIgnored;
781 };
782
joshualitt76e7fb62015-02-11 08:52:27 -0800783 BatchTracker fBatch;
784 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -0700785
786 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -0800787};
788
bsalomonabd30f52015-08-13 13:34:48 -0700789static GrDrawBatch* create_circle_batch(GrColor color,
790 const SkMatrix& viewMatrix,
791 bool useCoverageAA,
792 const SkRect& circle,
793 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000794 SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
joshualitt8059eb92014-12-29 15:10:07 -0800795 viewMatrix.mapPoints(&center, 1);
796 SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
797 SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000798
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000799 SkStrokeRec::Style style = stroke.getStyle();
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000800 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
801 SkStrokeRec::kHairline_Style == style;
802 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
skia.committer@gmail.com7e328512013-03-23 07:01:28 +0000803
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000804 SkScalar innerRadius = 0.0f;
805 SkScalar outerRadius = radius;
806 SkScalar halfWidth = 0;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000807 if (hasStroke) {
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000808 if (SkScalarNearlyZero(strokeWidth)) {
809 halfWidth = SK_ScalarHalf;
810 } else {
811 halfWidth = SkScalarHalf(strokeWidth);
812 }
813
814 outerRadius += halfWidth;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000815 if (isStrokeOnly) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +0000816 innerRadius = radius - halfWidth;
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000817 }
818 }
819
bsalomonce1c8862014-12-15 07:11:22 -0800820 // The radii are outset for two reasons. First, it allows the shader to simply perform simpler
821 // computation because the computed alpha is zero, rather than 50%, at the radius.
822 // Second, the outer radius is used to compute the verts of the bounding box that is rendered
823 // and the outset ensures the box will cover all partially covered by the circle.
bsalomon@google.com58e30fe2013-04-01 19:01:20 +0000824 outerRadius += SK_ScalarHalf;
825 innerRadius -= SK_ScalarHalf;
826
joshualitt76e7fb62015-02-11 08:52:27 -0800827 CircleBatch::Geometry geometry;
828 geometry.fViewMatrix = viewMatrix;
829 geometry.fColor = color;
830 geometry.fInnerRadius = innerRadius;
831 geometry.fOuterRadius = outerRadius;
832 geometry.fStroke = isStrokeOnly && innerRadius > 0;
joshualittd96a67b2015-05-05 14:09:05 -0700833 geometry.fDevBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
834 center.fX + outerRadius, center.fY + outerRadius);
commit-bot@chromium.org0a6cb602013-04-11 15:05:37 +0000835
joshualitt3e708c52015-04-30 13:49:27 -0700836 return CircleBatch::Create(geometry);
837}
838
robertphillipsea461502015-05-26 11:38:03 -0700839void GrOvalRenderer::DrawCircle(GrDrawTarget* target,
joshualittae3d63a2015-07-13 08:44:06 -0700840 const GrPipelineBuilder& pipelineBuilder,
joshualitt3e708c52015-04-30 13:49:27 -0700841 GrColor color,
842 const SkMatrix& viewMatrix,
843 bool useCoverageAA,
844 const SkRect& circle,
845 const SkStrokeRec& stroke) {
bsalomonabd30f52015-08-13 13:34:48 -0700846 SkAutoTUnref<GrDrawBatch> batch(create_circle_batch(color, viewMatrix, useCoverageAA, circle,
847 stroke));
joshualittae3d63a2015-07-13 08:44:06 -0700848 target->drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000849}
850
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +0000851///////////////////////////////////////////////////////////////////////////////
852
bsalomonabd30f52015-08-13 13:34:48 -0700853class EllipseBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -0800854public:
reed1b55a962015-09-17 20:16:13 -0700855 DEFINE_BATCH_CLASS_ID
856
joshualitt76e7fb62015-02-11 08:52:27 -0800857 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -0800858 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -0700859 SkRect fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -0800860 SkScalar fXRadius;
861 SkScalar fYRadius;
862 SkScalar fInnerXRadius;
863 SkScalar fInnerYRadius;
reed1b55a962015-09-17 20:16:13 -0700864 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -0800865 bool fStroke;
joshualitt76e7fb62015-02-11 08:52:27 -0800866 };
867
halcanary385fe4d2015-08-26 13:07:48 -0700868 static GrDrawBatch* Create(const Geometry& geometry) { return new EllipseBatch(geometry); }
joshualitt76e7fb62015-02-11 08:52:27 -0800869
mtklein36352bf2015-03-25 18:17:31 -0700870 const char* name() const override { return "EllipseBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -0800871
ethannicholasff210322015-11-24 12:10:10 -0800872 void computePipelineOptimizations(GrInitInvariantOutput* color,
873 GrInitInvariantOutput* coverage,
874 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -0800875 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -0800876 color->setKnownFourComponents(fGeoData[0].fColor);
877 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -0800878 }
879
bsalomone46f9fe2015-08-18 06:05:14 -0700880private:
ethannicholasff210322015-11-24 12:10:10 -0800881 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -0800882 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -0800883 if (!overrides.readsCoverage()) {
joshualitt76e7fb62015-02-11 08:52:27 -0800884 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -0800885 }
ethannicholasff210322015-11-24 12:10:10 -0800886 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -0800887
888 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -0800889 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -0800890 fBatch.fColor = fGeoData[0].fColor;
891 fBatch.fStroke = fGeoData[0].fStroke;
ethannicholasff210322015-11-24 12:10:10 -0800892 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
893 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -0800894 }
895
joshualitt144c3c82015-11-30 12:30:13 -0800896 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -0800897 SkMatrix invert;
898 if (!this->viewMatrix().invert(&invert)) {
899 return;
900 }
901
902 // Setup geometry processor
903 SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
904 this->stroke(),
joshualittb8c241a2015-05-19 08:23:30 -0700905 invert,
906 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -0800907
bsalomon75398562015-08-17 12:55:38 -0700908 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -0800909
joshualitt76e7fb62015-02-11 08:52:27 -0800910 int instanceCount = fGeoData.count();
bsalomonb5238a72015-05-05 07:49:49 -0700911 QuadHelper helper;
joshualitt76e7fb62015-02-11 08:52:27 -0800912 size_t vertexStride = gp->getVertexStride();
joshualitt19e00582015-02-11 17:36:30 -0800913 SkASSERT(vertexStride == sizeof(EllipseVertex));
bsalomonb5238a72015-05-05 07:49:49 -0700914 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
bsalomon75398562015-08-17 12:55:38 -0700915 helper.init(target, vertexStride, instanceCount));
bsalomonb5238a72015-05-05 07:49:49 -0700916 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800917 return;
918 }
919
bsalomon8415abe2015-05-04 11:41:41 -0700920 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800921 const Geometry& geom = fGeoData[i];
bsalomon8415abe2015-05-04 11:41:41 -0700922
brianosmanbb2ff942016-02-11 14:15:18 -0800923 GrColor color = geom.fColor;
bsalomonb5238a72015-05-05 07:49:49 -0700924 SkScalar xRadius = geom.fXRadius;
925 SkScalar yRadius = geom.fYRadius;
joshualitt76e7fb62015-02-11 08:52:27 -0800926
927 // Compute the reciprocals of the radii here to save time in the shader
928 SkScalar xRadRecip = SkScalarInvert(xRadius);
929 SkScalar yRadRecip = SkScalarInvert(yRadius);
bsalomonb5238a72015-05-05 07:49:49 -0700930 SkScalar xInnerRadRecip = SkScalarInvert(geom.fInnerXRadius);
931 SkScalar yInnerRadRecip = SkScalarInvert(geom.fInnerYRadius);
joshualitt76e7fb62015-02-11 08:52:27 -0800932
bsalomonb5238a72015-05-05 07:49:49 -0700933 const SkRect& bounds = geom.fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -0800934
935 // The inner radius in the vertex data must be specified in normalized space.
936 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -0800937 verts[0].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800938 verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
939 verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
940 verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
941
942 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -0800943 verts[1].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800944 verts[1].fOffset = SkPoint::Make(-xRadius, yRadius);
945 verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
946 verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
947
948 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -0800949 verts[2].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800950 verts[2].fOffset = SkPoint::Make(xRadius, yRadius);
951 verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
952 verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
953
954 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -0800955 verts[3].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800956 verts[3].fOffset = SkPoint::Make(xRadius, -yRadius);
957 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
958 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
959
bsalomonb5238a72015-05-05 07:49:49 -0700960 verts += kVerticesPerQuad;
joshualitt76e7fb62015-02-11 08:52:27 -0800961 }
bsalomon75398562015-08-17 12:55:38 -0700962 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -0800963 }
964
965 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
966
reed1b55a962015-09-17 20:16:13 -0700967 EllipseBatch(const Geometry& geometry) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -0800968 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -0700969
970 this->setBounds(geometry.fDevBounds);
joshualitt76e7fb62015-02-11 08:52:27 -0800971 }
972
bsalomoncb02b382015-08-12 11:14:50 -0700973 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -0700974 EllipseBatch* that = t->cast<EllipseBatch>();
975
976 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
977 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -0700978 return false;
979 }
980
joshualitt76e7fb62015-02-11 08:52:27 -0800981 if (this->stroke() != that->stroke()) {
982 return false;
983 }
984
985 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
986 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
987 return false;
988 }
989
990 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -0700991 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -0800992 return true;
993 }
994
995 GrColor color() const { return fBatch.fColor; }
996 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
997 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
998 bool stroke() const { return fBatch.fStroke; }
999
1000 struct BatchTracker {
1001 GrColor fColor;
1002 bool fStroke;
1003 bool fUsesLocalCoords;
1004 bool fColorIgnored;
1005 bool fCoverageIgnored;
1006 };
1007
joshualitt76e7fb62015-02-11 08:52:27 -08001008 BatchTracker fBatch;
1009 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -07001010
1011 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -08001012};
1013
bsalomonabd30f52015-08-13 13:34:48 -07001014static GrDrawBatch* create_ellipse_batch(GrColor color,
1015 const SkMatrix& viewMatrix,
1016 bool useCoverageAA,
1017 const SkRect& ellipse,
1018 const SkStrokeRec& stroke) {
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001019#ifdef SK_DEBUG
1020 {
1021 // we should have checked for this previously
joshualitt8059eb92014-12-29 15:10:07 -08001022 bool isAxisAlignedEllipse = viewMatrix.rectStaysRect();
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001023 SkASSERT(useCoverageAA && isAxisAlignedEllipse);
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001024 }
1025#endif
1026
commit-bot@chromium.org0c888282013-04-19 19:01:45 +00001027 // do any matrix crunching before we reset the draw state for device coords
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +00001028 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
joshualitt8059eb92014-12-29 15:10:07 -08001029 viewMatrix.mapPoints(&center, 1);
commit-bot@chromium.org0c888282013-04-19 19:01:45 +00001030 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
1031 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
joshualitt8059eb92014-12-29 15:10:07 -08001032 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius +
1033 viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius);
1034 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius +
1035 viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius);
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001036
commit-bot@chromium.org0c888282013-04-19 19:01:45 +00001037 // do (potentially) anisotropic mapping of stroke
1038 SkVector scaledStroke;
1039 SkScalar strokeWidth = stroke.getWidth();
joshualitt8059eb92014-12-29 15:10:07 -08001040 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
1041 viewMatrix[SkMatrix::kMSkewY]));
1042 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
1043 viewMatrix[SkMatrix::kMScaleY]));
commit-bot@chromium.org0c888282013-04-19 19:01:45 +00001044
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001045 SkStrokeRec::Style style = stroke.getStyle();
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001046 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1047 SkStrokeRec::kHairline_Style == style;
1048 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001049
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001050 SkScalar innerXRadius = 0;
1051 SkScalar innerYRadius = 0;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001052 if (hasStroke) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001053 if (SkScalarNearlyZero(scaledStroke.length())) {
1054 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1055 } else {
1056 scaledStroke.scale(SK_ScalarHalf);
1057 }
1058
1059 // we only handle thick strokes for near-circular ellipses
1060 if (scaledStroke.length() > SK_ScalarHalf &&
1061 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001062 return nullptr;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001063 }
1064
1065 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1066 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
1067 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
halcanary96fcdcc2015-08-27 07:41:13 -07001068 return nullptr;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001069 }
1070
1071 // this is legit only if scale & translation (which should be the case at the moment)
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001072 if (isStrokeOnly) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001073 innerXRadius = xRadius - scaledStroke.fX;
1074 innerYRadius = yRadius - scaledStroke.fY;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001075 }
1076
1077 xRadius += scaledStroke.fX;
1078 yRadius += scaledStroke.fY;
1079 }
1080
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001081 // We've extended the outer x radius out half a pixel to antialias.
commit-bot@chromium.org0a6cb602013-04-11 15:05:37 +00001082 // This will also expand the rect so all the pixels will be captured.
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001083 // TODO: Consider if we should use sqrt(2)/2 instead
brianosmanc6052ac2016-02-12 10:20:00 -08001084 SkScalar geoXRadius = xRadius + SK_ScalarHalf;
1085 SkScalar geoYRadius = yRadius + SK_ScalarHalf;
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001086
joshualitt76e7fb62015-02-11 08:52:27 -08001087 EllipseBatch::Geometry geometry;
1088 geometry.fViewMatrix = viewMatrix;
1089 geometry.fColor = color;
1090 geometry.fXRadius = xRadius;
1091 geometry.fYRadius = yRadius;
1092 geometry.fInnerXRadius = innerXRadius;
1093 geometry.fInnerYRadius = innerYRadius;
1094 geometry.fStroke = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
brianosmanc6052ac2016-02-12 10:20:00 -08001095 geometry.fDevBounds = SkRect::MakeLTRB(center.fX - geoXRadius, center.fY - geoYRadius,
1096 center.fX + geoXRadius, center.fY + geoYRadius);
commit-bot@chromium.org0a6cb602013-04-11 15:05:37 +00001097
joshualitt3e708c52015-04-30 13:49:27 -07001098 return EllipseBatch::Create(geometry);
1099}
1100
robertphillipsea461502015-05-26 11:38:03 -07001101bool GrOvalRenderer::DrawEllipse(GrDrawTarget* target,
joshualittae3d63a2015-07-13 08:44:06 -07001102 const GrPipelineBuilder& pipelineBuilder,
joshualitt3e708c52015-04-30 13:49:27 -07001103 GrColor color,
1104 const SkMatrix& viewMatrix,
1105 bool useCoverageAA,
1106 const SkRect& ellipse,
1107 const SkStrokeRec& stroke) {
bsalomonabd30f52015-08-13 13:34:48 -07001108 SkAutoTUnref<GrDrawBatch> batch(create_ellipse_batch(color, viewMatrix, useCoverageAA, ellipse,
1109 stroke));
joshualitt3e708c52015-04-30 13:49:27 -07001110 if (!batch) {
1111 return false;
1112 }
1113
joshualittae3d63a2015-07-13 08:44:06 -07001114 target->drawBatch(pipelineBuilder, batch);
jvanverth@google.comc4f2eca2013-04-16 12:30:35 +00001115 return true;
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001116}
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001117
joshualitt76e7fb62015-02-11 08:52:27 -08001118/////////////////////////////////////////////////////////////////////////////////////////////////
1119
bsalomonabd30f52015-08-13 13:34:48 -07001120class DIEllipseBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -08001121public:
reed1b55a962015-09-17 20:16:13 -07001122 DEFINE_BATCH_CLASS_ID
1123
joshualitt76e7fb62015-02-11 08:52:27 -08001124 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -08001125 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -07001126 SkRect fBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001127 SkScalar fXRadius;
1128 SkScalar fYRadius;
1129 SkScalar fInnerXRadius;
1130 SkScalar fInnerYRadius;
1131 SkScalar fGeoDx;
1132 SkScalar fGeoDy;
reed1b55a962015-09-17 20:16:13 -07001133 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -08001134 DIEllipseEdgeEffect::Mode fMode;
joshualitt76e7fb62015-02-11 08:52:27 -08001135 };
1136
bsalomonabd30f52015-08-13 13:34:48 -07001137 static GrDrawBatch* Create(const Geometry& geometry, const SkRect& bounds) {
halcanary385fe4d2015-08-26 13:07:48 -07001138 return new DIEllipseBatch(geometry, bounds);
joshualitt76e7fb62015-02-11 08:52:27 -08001139 }
1140
mtklein36352bf2015-03-25 18:17:31 -07001141 const char* name() const override { return "DIEllipseBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -08001142
ethannicholasff210322015-11-24 12:10:10 -08001143 void computePipelineOptimizations(GrInitInvariantOutput* color,
1144 GrInitInvariantOutput* coverage,
1145 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001146 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -08001147 color->setKnownFourComponents(fGeoData[0].fColor);
1148 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -08001149 }
1150
bsalomone46f9fe2015-08-18 06:05:14 -07001151private:
1152
ethannicholasff210322015-11-24 12:10:10 -08001153 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -08001154 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -08001155 if (!overrides.readsColor()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001156 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -08001157 }
ethannicholasff210322015-11-24 12:10:10 -08001158 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -08001159
1160 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -08001161 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -08001162 fBatch.fColor = fGeoData[0].fColor;
1163 fBatch.fMode = fGeoData[0].fMode;
ethannicholasff210322015-11-24 12:10:10 -08001164 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
1165 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -08001166 }
1167
joshualitt144c3c82015-11-30 12:30:13 -08001168 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001169 // Setup geometry processor
1170 SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(this->color(),
1171 this->viewMatrix(),
joshualittb8c241a2015-05-19 08:23:30 -07001172 this->mode(),
1173 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -08001174
bsalomon75398562015-08-17 12:55:38 -07001175 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -08001176
joshualitt76e7fb62015-02-11 08:52:27 -08001177 int instanceCount = fGeoData.count();
joshualitt76e7fb62015-02-11 08:52:27 -08001178 size_t vertexStride = gp->getVertexStride();
joshualitt19e00582015-02-11 17:36:30 -08001179 SkASSERT(vertexStride == sizeof(DIEllipseVertex));
bsalomonb5238a72015-05-05 07:49:49 -07001180 QuadHelper helper;
1181 DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(
bsalomon75398562015-08-17 12:55:38 -07001182 helper.init(target, vertexStride, instanceCount));
bsalomonb5238a72015-05-05 07:49:49 -07001183 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -08001184 return;
1185 }
1186
joshualitt76e7fb62015-02-11 08:52:27 -08001187 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -08001188 const Geometry& geom = fGeoData[i];
joshualitt76e7fb62015-02-11 08:52:27 -08001189
brianosmanbb2ff942016-02-11 14:15:18 -08001190 GrColor color = geom.fColor;
bsalomonb5238a72015-05-05 07:49:49 -07001191 SkScalar xRadius = geom.fXRadius;
1192 SkScalar yRadius = geom.fYRadius;
joshualitt76e7fb62015-02-11 08:52:27 -08001193
bsalomonb5238a72015-05-05 07:49:49 -07001194 const SkRect& bounds = geom.fBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001195
1196 // This adjusts the "radius" to include the half-pixel border
reed80ea19c2015-05-12 10:37:34 -07001197 SkScalar offsetDx = geom.fGeoDx / xRadius;
1198 SkScalar offsetDy = geom.fGeoDy / yRadius;
joshualitt76e7fb62015-02-11 08:52:27 -08001199
reed80ea19c2015-05-12 10:37:34 -07001200 SkScalar innerRatioX = xRadius / geom.fInnerXRadius;
1201 SkScalar innerRatioY = yRadius / geom.fInnerYRadius;
joshualitt76e7fb62015-02-11 08:52:27 -08001202
1203 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -08001204 verts[0].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001205 verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
1206 verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
1207
1208 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -08001209 verts[1].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001210 verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
1211 verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
1212
1213 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -08001214 verts[2].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001215 verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
1216 verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
1217
1218 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -08001219 verts[3].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001220 verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
1221 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
1222
bsalomonb5238a72015-05-05 07:49:49 -07001223 verts += kVerticesPerQuad;
joshualitt76e7fb62015-02-11 08:52:27 -08001224 }
bsalomon75398562015-08-17 12:55:38 -07001225 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -08001226 }
1227
1228 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1229
reed1b55a962015-09-17 20:16:13 -07001230 DIEllipseBatch(const Geometry& geometry, const SkRect& bounds) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001231 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -07001232
1233 this->setBounds(bounds);
joshualitt76e7fb62015-02-11 08:52:27 -08001234 }
1235
bsalomoncb02b382015-08-12 11:14:50 -07001236 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -07001237 DIEllipseBatch* that = t->cast<DIEllipseBatch>();
1238 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1239 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -07001240 return false;
1241 }
1242
joshualitt76e7fb62015-02-11 08:52:27 -08001243 if (this->mode() != that->mode()) {
1244 return false;
1245 }
1246
joshualittd96a67b2015-05-05 14:09:05 -07001247 // TODO rewrite to allow positioning on CPU
1248 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
joshualitt76e7fb62015-02-11 08:52:27 -08001249 return false;
1250 }
1251
1252 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -07001253 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -08001254 return true;
1255 }
1256
1257 GrColor color() const { return fBatch.fColor; }
1258 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1259 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1260 DIEllipseEdgeEffect::Mode mode() const { return fBatch.fMode; }
1261
1262 struct BatchTracker {
1263 GrColor fColor;
1264 DIEllipseEdgeEffect::Mode fMode;
1265 bool fUsesLocalCoords;
1266 bool fColorIgnored;
1267 bool fCoverageIgnored;
1268 };
1269
joshualitt76e7fb62015-02-11 08:52:27 -08001270 BatchTracker fBatch;
1271 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -07001272
1273 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -08001274};
1275
bsalomonabd30f52015-08-13 13:34:48 -07001276static GrDrawBatch* create_diellipse_batch(GrColor color,
1277 const SkMatrix& viewMatrix,
1278 bool useCoverageAA,
1279 const SkRect& ellipse,
1280 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +00001281 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001282 SkScalar xRadius = SkScalarHalf(ellipse.width());
skia.committer@gmail.com6fc1b492013-09-06 07:01:45 +00001283 SkScalar yRadius = SkScalarHalf(ellipse.height());
1284
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001285 SkStrokeRec::Style style = stroke.getStyle();
skia.committer@gmail.com6fc1b492013-09-06 07:01:45 +00001286 DIEllipseEdgeEffect::Mode mode = (SkStrokeRec::kStroke_Style == style) ?
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001287 DIEllipseEdgeEffect::kStroke :
skia.committer@gmail.com6fc1b492013-09-06 07:01:45 +00001288 (SkStrokeRec::kHairline_Style == style) ?
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001289 DIEllipseEdgeEffect::kHairline : DIEllipseEdgeEffect::kFill;
1290
1291 SkScalar innerXRadius = 0;
1292 SkScalar innerYRadius = 0;
1293 if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
1294 SkScalar strokeWidth = stroke.getWidth();
1295
1296 if (SkScalarNearlyZero(strokeWidth)) {
1297 strokeWidth = SK_ScalarHalf;
1298 } else {
1299 strokeWidth *= SK_ScalarHalf;
1300 }
1301
1302 // we only handle thick strokes for near-circular ellipses
1303 if (strokeWidth > SK_ScalarHalf &&
1304 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001305 return nullptr;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001306 }
1307
1308 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1309 if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
1310 strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
halcanary96fcdcc2015-08-27 07:41:13 -07001311 return nullptr;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001312 }
1313
1314 // set inner radius (if needed)
1315 if (SkStrokeRec::kStroke_Style == style) {
1316 innerXRadius = xRadius - strokeWidth;
1317 innerYRadius = yRadius - strokeWidth;
1318 }
1319
1320 xRadius += strokeWidth;
1321 yRadius += strokeWidth;
1322 }
1323 if (DIEllipseEdgeEffect::kStroke == mode) {
1324 mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kStroke :
1325 DIEllipseEdgeEffect::kFill;
1326 }
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001327
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001328 // This expands the outer rect so that after CTM we end up with a half-pixel border
joshualitt8059eb92014-12-29 15:10:07 -08001329 SkScalar a = viewMatrix[SkMatrix::kMScaleX];
1330 SkScalar b = viewMatrix[SkMatrix::kMSkewX];
1331 SkScalar c = viewMatrix[SkMatrix::kMSkewY];
1332 SkScalar d = viewMatrix[SkMatrix::kMScaleY];
reed80ea19c2015-05-12 10:37:34 -07001333 SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
1334 SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001335
joshualitt76e7fb62015-02-11 08:52:27 -08001336 DIEllipseBatch::Geometry geometry;
1337 geometry.fViewMatrix = viewMatrix;
1338 geometry.fColor = color;
1339 geometry.fXRadius = xRadius;
1340 geometry.fYRadius = yRadius;
1341 geometry.fInnerXRadius = innerXRadius;
1342 geometry.fInnerYRadius = innerYRadius;
1343 geometry.fGeoDx = geoDx;
1344 geometry.fGeoDy = geoDy;
1345 geometry.fMode = mode;
joshualittd96a67b2015-05-05 14:09:05 -07001346 geometry.fBounds = SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
1347 center.fX + xRadius + geoDx, center.fY + yRadius + geoDy);
egdaniel9ef1bb12015-04-20 12:28:57 -07001348
joshualittd96a67b2015-05-05 14:09:05 -07001349 SkRect devBounds = geometry.fBounds;
1350 viewMatrix.mapRect(&devBounds);
1351 return DIEllipseBatch::Create(geometry, devBounds);
joshualitt3e708c52015-04-30 13:49:27 -07001352}
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001353
robertphillipsea461502015-05-26 11:38:03 -07001354bool GrOvalRenderer::DrawDIEllipse(GrDrawTarget* target,
joshualittae3d63a2015-07-13 08:44:06 -07001355 const GrPipelineBuilder& pipelineBuilder,
joshualitt3e708c52015-04-30 13:49:27 -07001356 GrColor color,
1357 const SkMatrix& viewMatrix,
1358 bool useCoverageAA,
1359 const SkRect& ellipse,
1360 const SkStrokeRec& stroke) {
bsalomonabd30f52015-08-13 13:34:48 -07001361 SkAutoTUnref<GrDrawBatch> batch(create_diellipse_batch(color, viewMatrix, useCoverageAA,
1362 ellipse, stroke));
joshualitt3e708c52015-04-30 13:49:27 -07001363 if (!batch) {
1364 return false;
1365 }
joshualittae3d63a2015-07-13 08:44:06 -07001366 target->drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001367 return true;
1368}
1369
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001370///////////////////////////////////////////////////////////////////////////////
1371
1372static const uint16_t gRRectIndices[] = {
1373 // corners
1374 0, 1, 5, 0, 5, 4,
1375 2, 3, 7, 2, 7, 6,
1376 8, 9, 13, 8, 13, 12,
1377 10, 11, 15, 10, 15, 14,
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001378
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001379 // edges
1380 1, 2, 6, 1, 6, 5,
1381 4, 5, 9, 4, 9, 8,
1382 6, 7, 11, 6, 11, 10,
1383 9, 10, 14, 9, 14, 13,
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001384
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001385 // center
1386 // we place this at the end so that we can ignore these indices when rendering stroke-only
1387 5, 6, 10, 5, 10, 9
1388};
1389
joshualitt5ead6da2014-10-22 16:00:29 -07001390static const int kIndicesPerStrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
1391static const int kIndicesPerRRect = SK_ARRAY_COUNT(gRRectIndices);
1392static const int kVertsPerRRect = 16;
1393static const int kNumRRectsInIndexBuffer = 256;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001394
bsalomoned0bcad2015-05-04 10:36:42 -07001395GR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1396GR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1397static const GrIndexBuffer* ref_rrect_index_buffer(bool strokeOnly,
1398 GrResourceProvider* resourceProvider) {
1399 GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1400 GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1401 if (strokeOnly) {
bsalomoneae62002015-07-31 13:59:30 -07001402 return resourceProvider->findOrCreateInstancedIndexBuffer(
bsalomoned0bcad2015-05-04 10:36:42 -07001403 gRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1404 gStrokeRRectOnlyIndexBufferKey);
1405 } else {
bsalomoneae62002015-07-31 13:59:30 -07001406 return resourceProvider->findOrCreateInstancedIndexBuffer(
bsalomoned0bcad2015-05-04 10:36:42 -07001407 gRRectIndices, kIndicesPerRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1408 gRRectOnlyIndexBufferKey);
1409
1410 }
1411}
1412
robertphillipsea461502015-05-26 11:38:03 -07001413bool GrOvalRenderer::DrawDRRect(GrDrawTarget* target,
joshualittae3d63a2015-07-13 08:44:06 -07001414 const GrPipelineBuilder& pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -08001415 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -08001416 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -08001417 bool useAA,
1418 const SkRRect& origOuter,
1419 const SkRRect& origInner) {
joshualittae3d63a2015-07-13 08:44:06 -07001420 bool applyAA = useAA && !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
joshualitt4421a4c2015-07-13 09:36:41 -07001421 GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001422 if (!origInner.isEmpty()) {
1423 SkTCopyOnFirstWrite<SkRRect> inner(origInner);
joshualitt8059eb92014-12-29 15:10:07 -08001424 if (!viewMatrix.isIdentity()) {
1425 if (!origInner.transform(viewMatrix, inner.writable())) {
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001426 return false;
1427 }
1428 }
joshualittb0a8a372014-09-23 09:50:21 -07001429 GrPrimitiveEdgeType edgeType = applyAA ?
1430 kInverseFillAA_GrProcessorEdgeType :
1431 kInverseFillBW_GrProcessorEdgeType;
joshualitt2e3b3e32014-12-09 13:31:14 -08001432 // TODO this needs to be a geometry processor
joshualittb0a8a372014-09-23 09:50:21 -07001433 GrFragmentProcessor* fp = GrRRectEffect::Create(edgeType, *inner);
halcanary96fcdcc2015-08-27 07:41:13 -07001434 if (nullptr == fp) {
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001435 return false;
1436 }
joshualitt4421a4c2015-07-13 09:36:41 -07001437 arfps.set(&pipelineBuilder);
bsalomonac856c92015-08-27 06:30:17 -07001438 arfps.addCoverageFragmentProcessor(fp)->unref();
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001439 }
1440
1441 SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle);
robertphillipsea461502015-05-26 11:38:03 -07001442 if (DrawRRect(target, pipelineBuilder, color, viewMatrix, useAA, origOuter, fillRec)) {
bsalomon8af05232014-06-03 06:34:58 -07001443 return true;
1444 }
1445
1446 SkASSERT(!origOuter.isEmpty());
1447 SkTCopyOnFirstWrite<SkRRect> outer(origOuter);
joshualitt8059eb92014-12-29 15:10:07 -08001448 if (!viewMatrix.isIdentity()) {
1449 if (!origOuter.transform(viewMatrix, outer.writable())) {
bsalomon8af05232014-06-03 06:34:58 -07001450 return false;
1451 }
1452 }
joshualittb0a8a372014-09-23 09:50:21 -07001453 GrPrimitiveEdgeType edgeType = applyAA ? kFillAA_GrProcessorEdgeType :
joshualitt76e7fb62015-02-11 08:52:27 -08001454 kFillBW_GrProcessorEdgeType;
joshualittb0a8a372014-09-23 09:50:21 -07001455 GrFragmentProcessor* effect = GrRRectEffect::Create(edgeType, *outer);
halcanary96fcdcc2015-08-27 07:41:13 -07001456 if (nullptr == effect) {
bsalomon8af05232014-06-03 06:34:58 -07001457 return false;
1458 }
joshualitt4421a4c2015-07-13 09:36:41 -07001459 if (!arfps.isSet()) {
1460 arfps.set(&pipelineBuilder);
bsalomon8af05232014-06-03 06:34:58 -07001461 }
joshualittd27f73e2014-12-29 07:43:36 -08001462
1463 SkMatrix invert;
joshualitt8059eb92014-12-29 15:10:07 -08001464 if (!viewMatrix.invert(&invert)) {
bsalomon8af05232014-06-03 06:34:58 -07001465 return false;
1466 }
joshualittd27f73e2014-12-29 07:43:36 -08001467
bsalomonac856c92015-08-27 06:30:17 -07001468 arfps.addCoverageFragmentProcessor(effect)->unref();
bsalomon8af05232014-06-03 06:34:58 -07001469 SkRect bounds = outer->getBounds();
1470 if (applyAA) {
1471 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1472 }
joshualitt04194f32016-01-13 10:08:27 -08001473 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(),
1474 bounds, nullptr, &invert));
1475 target->drawBatch(pipelineBuilder, batch);
bsalomon8af05232014-06-03 06:34:58 -07001476 return true;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001477}
1478
joshualitt76e7fb62015-02-11 08:52:27 -08001479///////////////////////////////////////////////////////////////////////////////////////////////////
1480
bsalomonabd30f52015-08-13 13:34:48 -07001481class RRectCircleRendererBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -08001482public:
reed1b55a962015-09-17 20:16:13 -07001483 DEFINE_BATCH_CLASS_ID
1484
joshualitt76e7fb62015-02-11 08:52:27 -08001485 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -08001486 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -07001487 SkRect fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001488 SkScalar fInnerRadius;
1489 SkScalar fOuterRadius;
reed1b55a962015-09-17 20:16:13 -07001490 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -08001491 bool fStroke;
joshualitt76e7fb62015-02-11 08:52:27 -08001492 };
1493
bsalomonabd30f52015-08-13 13:34:48 -07001494 static GrDrawBatch* Create(const Geometry& geometry) {
halcanary385fe4d2015-08-26 13:07:48 -07001495 return new RRectCircleRendererBatch(geometry);
joshualitt76e7fb62015-02-11 08:52:27 -08001496 }
1497
mtklein36352bf2015-03-25 18:17:31 -07001498 const char* name() const override { return "RRectCircleBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -08001499
ethannicholasff210322015-11-24 12:10:10 -08001500 void computePipelineOptimizations(GrInitInvariantOutput* color,
1501 GrInitInvariantOutput* coverage,
1502 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001503 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -08001504 color->setKnownFourComponents(fGeoData[0].fColor);
1505 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -08001506 }
1507
bsalomone46f9fe2015-08-18 06:05:14 -07001508private:
ethannicholasff210322015-11-24 12:10:10 -08001509 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -08001510 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -08001511 if (!overrides.readsColor()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001512 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -08001513 }
ethannicholasff210322015-11-24 12:10:10 -08001514 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -08001515
1516 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -08001517 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -08001518 fBatch.fColor = fGeoData[0].fColor;
1519 fBatch.fStroke = fGeoData[0].fStroke;
ethannicholasff210322015-11-24 12:10:10 -08001520 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
1521 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -08001522 }
1523
joshualitt144c3c82015-11-30 12:30:13 -08001524 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001525 // reset to device coordinates
1526 SkMatrix invert;
1527 if (!this->viewMatrix().invert(&invert)) {
1528 SkDebugf("Failed to invert\n");
1529 return;
1530 }
1531
1532 // Setup geometry processor
1533 SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
1534 this->stroke(),
joshualittb8c241a2015-05-19 08:23:30 -07001535 invert,
1536 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -08001537
bsalomon75398562015-08-17 12:55:38 -07001538 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -08001539
joshualitt76e7fb62015-02-11 08:52:27 -08001540 int instanceCount = fGeoData.count();
joshualitt76e7fb62015-02-11 08:52:27 -08001541 size_t vertexStride = gp->getVertexStride();
1542 SkASSERT(vertexStride == sizeof(CircleVertex));
1543
bsalomonb5238a72015-05-05 07:49:49 -07001544 // drop out the middle quad if we're stroked
1545 int indicesPerInstance = this->stroke() ? kIndicesPerStrokeRRect : kIndicesPerRRect;
bsalomoned0bcad2015-05-04 10:36:42 -07001546 SkAutoTUnref<const GrIndexBuffer> indexBuffer(
bsalomon75398562015-08-17 12:55:38 -07001547 ref_rrect_index_buffer(this->stroke(), target->resourceProvider()));
joshualitt76e7fb62015-02-11 08:52:27 -08001548
bsalomonb5238a72015-05-05 07:49:49 -07001549 InstancedHelper helper;
bsalomon75398562015-08-17 12:55:38 -07001550 CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target,
bsalomonb5238a72015-05-05 07:49:49 -07001551 kTriangles_GrPrimitiveType, vertexStride, indexBuffer, kVertsPerRRect,
1552 indicesPerInstance, instanceCount));
1553 if (!verts || !indexBuffer) {
joshualitt4b31de82015-03-05 14:33:41 -08001554 SkDebugf("Could not allocate vertices\n");
1555 return;
1556 }
1557
joshualitt76e7fb62015-02-11 08:52:27 -08001558 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -08001559 const Geometry& args = fGeoData[i];
joshualitt76e7fb62015-02-11 08:52:27 -08001560
brianosmanbb2ff942016-02-11 14:15:18 -08001561 GrColor color = args.fColor;
joshualitt76e7fb62015-02-11 08:52:27 -08001562 SkScalar outerRadius = args.fOuterRadius;
1563
egdanielbc227142015-04-21 06:28:08 -07001564 const SkRect& bounds = args.fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001565
1566 SkScalar yCoords[4] = {
1567 bounds.fTop,
1568 bounds.fTop + outerRadius,
1569 bounds.fBottom - outerRadius,
1570 bounds.fBottom
1571 };
1572
1573 SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
1574 // The inner radius in the vertex data must be specified in normalized space.
1575 SkScalar innerRadius = args.fInnerRadius / args.fOuterRadius;
1576 for (int i = 0; i < 4; ++i) {
1577 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001578 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001579 verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
1580 verts->fOuterRadius = outerRadius;
1581 verts->fInnerRadius = innerRadius;
1582 verts++;
1583
1584 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001585 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001586 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1587 verts->fOuterRadius = outerRadius;
1588 verts->fInnerRadius = innerRadius;
1589 verts++;
1590
1591 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001592 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001593 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1594 verts->fOuterRadius = outerRadius;
1595 verts->fInnerRadius = innerRadius;
1596 verts++;
1597
1598 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001599 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001600 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
1601 verts->fOuterRadius = outerRadius;
1602 verts->fInnerRadius = innerRadius;
1603 verts++;
1604 }
1605 }
1606
bsalomon75398562015-08-17 12:55:38 -07001607 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -08001608 }
1609
1610 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1611
reed1b55a962015-09-17 20:16:13 -07001612 RRectCircleRendererBatch(const Geometry& geometry) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001613 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -07001614
1615 this->setBounds(geometry.fDevBounds);
joshualitt76e7fb62015-02-11 08:52:27 -08001616 }
1617
bsalomoncb02b382015-08-12 11:14:50 -07001618 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -07001619 RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>();
1620 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1621 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -07001622 return false;
1623 }
1624
joshualitt76e7fb62015-02-11 08:52:27 -08001625 if (this->stroke() != that->stroke()) {
1626 return false;
1627 }
1628
1629 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1630 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1631 return false;
1632 }
1633
1634 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -07001635 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -08001636 return true;
1637 }
1638
1639 GrColor color() const { return fBatch.fColor; }
1640 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1641 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1642 bool stroke() const { return fBatch.fStroke; }
1643
1644 struct BatchTracker {
1645 GrColor fColor;
1646 bool fStroke;
1647 bool fUsesLocalCoords;
1648 bool fColorIgnored;
1649 bool fCoverageIgnored;
1650 };
1651
joshualitt76e7fb62015-02-11 08:52:27 -08001652 BatchTracker fBatch;
1653 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -07001654
1655 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -08001656};
1657
bsalomonabd30f52015-08-13 13:34:48 -07001658class RRectEllipseRendererBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -08001659public:
reed1b55a962015-09-17 20:16:13 -07001660 DEFINE_BATCH_CLASS_ID
1661
joshualitt76e7fb62015-02-11 08:52:27 -08001662 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -08001663 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -07001664 SkRect fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001665 SkScalar fXRadius;
1666 SkScalar fYRadius;
1667 SkScalar fInnerXRadius;
1668 SkScalar fInnerYRadius;
reed1b55a962015-09-17 20:16:13 -07001669 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -08001670 bool fStroke;
joshualitt76e7fb62015-02-11 08:52:27 -08001671 };
1672
bsalomonabd30f52015-08-13 13:34:48 -07001673 static GrDrawBatch* Create(const Geometry& geometry) {
halcanary385fe4d2015-08-26 13:07:48 -07001674 return new RRectEllipseRendererBatch(geometry);
joshualitt76e7fb62015-02-11 08:52:27 -08001675 }
1676
mtklein36352bf2015-03-25 18:17:31 -07001677 const char* name() const override { return "RRectEllipseRendererBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -08001678
ethannicholasff210322015-11-24 12:10:10 -08001679 void computePipelineOptimizations(GrInitInvariantOutput* color,
1680 GrInitInvariantOutput* coverage,
1681 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001682 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -08001683 color->setKnownFourComponents(fGeoData[0].fColor);
1684 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -08001685 }
1686
bsalomone46f9fe2015-08-18 06:05:14 -07001687private:
ethannicholasff210322015-11-24 12:10:10 -08001688 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -08001689 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -08001690 if (!overrides.readsColor()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001691 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -08001692 }
ethannicholasff210322015-11-24 12:10:10 -08001693 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -08001694
1695 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -08001696 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -08001697 fBatch.fColor = fGeoData[0].fColor;
1698 fBatch.fStroke = fGeoData[0].fStroke;
ethannicholasff210322015-11-24 12:10:10 -08001699 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
1700 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -08001701 }
1702
joshualitt144c3c82015-11-30 12:30:13 -08001703 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001704 // reset to device coordinates
1705 SkMatrix invert;
1706 if (!this->viewMatrix().invert(&invert)) {
1707 SkDebugf("Failed to invert\n");
1708 return;
1709 }
1710
1711 // Setup geometry processor
1712 SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
1713 this->stroke(),
joshualittb8c241a2015-05-19 08:23:30 -07001714 invert,
1715 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -08001716
bsalomon75398562015-08-17 12:55:38 -07001717 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -08001718
joshualitt76e7fb62015-02-11 08:52:27 -08001719 int instanceCount = fGeoData.count();
joshualitt76e7fb62015-02-11 08:52:27 -08001720 size_t vertexStride = gp->getVertexStride();
1721 SkASSERT(vertexStride == sizeof(EllipseVertex));
1722
bsalomonb5238a72015-05-05 07:49:49 -07001723 // drop out the middle quad if we're stroked
1724 int indicesPerInstance = this->stroke() ? kIndicesPerStrokeRRect : kIndicesPerRRect;
bsalomoned0bcad2015-05-04 10:36:42 -07001725 SkAutoTUnref<const GrIndexBuffer> indexBuffer(
bsalomon75398562015-08-17 12:55:38 -07001726 ref_rrect_index_buffer(this->stroke(), target->resourceProvider()));
joshualitt76e7fb62015-02-11 08:52:27 -08001727
bsalomonb5238a72015-05-05 07:49:49 -07001728 InstancedHelper helper;
1729 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
bsalomon75398562015-08-17 12:55:38 -07001730 helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer,
bsalomonb5238a72015-05-05 07:49:49 -07001731 kVertsPerRRect, indicesPerInstance, instanceCount));
1732 if (!verts || !indexBuffer) {
joshualitt4b31de82015-03-05 14:33:41 -08001733 SkDebugf("Could not allocate vertices\n");
1734 return;
1735 }
1736
joshualitt76e7fb62015-02-11 08:52:27 -08001737 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -08001738 const Geometry& args = fGeoData[i];
joshualitt76e7fb62015-02-11 08:52:27 -08001739
brianosmanbb2ff942016-02-11 14:15:18 -08001740 GrColor color = args.fColor;
1741
joshualitt76e7fb62015-02-11 08:52:27 -08001742 // Compute the reciprocals of the radii here to save time in the shader
1743 SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
1744 SkScalar yRadRecip = SkScalarInvert(args.fYRadius);
1745 SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
1746 SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
1747
1748 // Extend the radii out half a pixel to antialias.
1749 SkScalar xOuterRadius = args.fXRadius + SK_ScalarHalf;
1750 SkScalar yOuterRadius = args.fYRadius + SK_ScalarHalf;
1751
egdanielbc227142015-04-21 06:28:08 -07001752 const SkRect& bounds = args.fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001753
1754 SkScalar yCoords[4] = {
1755 bounds.fTop,
1756 bounds.fTop + yOuterRadius,
1757 bounds.fBottom - yOuterRadius,
1758 bounds.fBottom
1759 };
1760 SkScalar yOuterOffsets[4] = {
1761 yOuterRadius,
1762 SK_ScalarNearlyZero, // we're using inversesqrt() in shader, so can't be exactly 0
1763 SK_ScalarNearlyZero,
1764 yOuterRadius
1765 };
1766
1767 for (int i = 0; i < 4; ++i) {
1768 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001769 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001770 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1771 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1772 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1773 verts++;
1774
1775 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001776 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001777 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
1778 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1779 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1780 verts++;
1781
1782 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001783 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001784 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
1785 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1786 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1787 verts++;
1788
1789 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001790 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001791 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1792 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1793 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1794 verts++;
1795 }
1796 }
bsalomon75398562015-08-17 12:55:38 -07001797 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -08001798 }
1799
1800 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1801
reed1b55a962015-09-17 20:16:13 -07001802 RRectEllipseRendererBatch(const Geometry& geometry) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001803 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -07001804
1805 this->setBounds(geometry.fDevBounds);
joshualitt76e7fb62015-02-11 08:52:27 -08001806 }
1807
bsalomoncb02b382015-08-12 11:14:50 -07001808 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -07001809 RRectEllipseRendererBatch* that = t->cast<RRectEllipseRendererBatch>();
1810
1811 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1812 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -07001813 return false;
1814 }
1815
joshualitt76e7fb62015-02-11 08:52:27 -08001816 if (this->stroke() != that->stroke()) {
1817 return false;
1818 }
1819
1820 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1821 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1822 return false;
1823 }
1824
1825 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -07001826 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -08001827 return true;
1828 }
1829
1830 GrColor color() const { return fBatch.fColor; }
1831 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1832 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1833 bool stroke() const { return fBatch.fStroke; }
1834
1835 struct BatchTracker {
1836 GrColor fColor;
1837 bool fStroke;
1838 bool fUsesLocalCoords;
1839 bool fColorIgnored;
1840 bool fCoverageIgnored;
1841 };
1842
joshualitt76e7fb62015-02-11 08:52:27 -08001843 BatchTracker fBatch;
1844 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -07001845
1846 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -08001847};
1848
bsalomonabd30f52015-08-13 13:34:48 -07001849static GrDrawBatch* create_rrect_batch(GrColor color,
1850 const SkMatrix& viewMatrix,
1851 const SkRRect& rrect,
1852 const SkStrokeRec& stroke) {
joshualitt3e708c52015-04-30 13:49:27 -07001853 SkASSERT(viewMatrix.rectStaysRect());
1854 SkASSERT(rrect.isSimple());
1855 SkASSERT(!rrect.isOval());
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001856
joshualitt3e708c52015-04-30 13:49:27 -07001857 // RRect batchs only handle simple, but not too simple, rrects
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001858 // do any matrix crunching before we reset the draw state for device coords
1859 const SkRect& rrectBounds = rrect.getBounds();
joshualittd96a67b2015-05-05 14:09:05 -07001860 SkRect bounds;
1861 viewMatrix.mapRect(&bounds, rrectBounds);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001862
1863 SkVector radii = rrect.getSimpleRadii();
joshualitt8059eb92014-12-29 15:10:07 -08001864 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX +
1865 viewMatrix[SkMatrix::kMSkewY]*radii.fY);
1866 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX +
1867 viewMatrix[SkMatrix::kMScaleY]*radii.fY);
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001868
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001869 SkStrokeRec::Style style = stroke.getStyle();
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001870
1871 // do (potentially) anisotropic mapping of stroke
1872 SkVector scaledStroke;
1873 SkScalar strokeWidth = stroke.getWidth();
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001874
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001875 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1876 SkStrokeRec::kHairline_Style == style;
1877 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
1878
1879 if (hasStroke) {
1880 if (SkStrokeRec::kHairline_Style == style) {
1881 scaledStroke.set(1, 1);
1882 } else {
joshualitt8059eb92014-12-29 15:10:07 -08001883 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
1884 viewMatrix[SkMatrix::kMSkewY]));
1885 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
1886 viewMatrix[SkMatrix::kMScaleY]));
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001887 }
1888
1889 // if half of strokewidth is greater than radius, we don't handle that right now
1890 if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) {
halcanary96fcdcc2015-08-27 07:41:13 -07001891 return nullptr;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001892 }
1893 }
1894
1895 // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
1896 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
1897 // patch will have fractional coverage. This only matters when the interior is actually filled.
1898 // We could consider falling back to rect rendering here, since a tiny radius is
1899 // indistinguishable from a square corner.
1900 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001901 return nullptr;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001902 }
1903
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001904 // if the corners are circles, use the circle renderer
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001905 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001906 SkScalar innerRadius = 0.0f;
1907 SkScalar outerRadius = xRadius;
1908 SkScalar halfWidth = 0;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001909 if (hasStroke) {
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001910 if (SkScalarNearlyZero(scaledStroke.fX)) {
1911 halfWidth = SK_ScalarHalf;
1912 } else {
1913 halfWidth = SkScalarHalf(scaledStroke.fX);
1914 }
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001915
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001916 if (isStrokeOnly) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001917 innerRadius = xRadius - halfWidth;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001918 }
1919 outerRadius += halfWidth;
joshualittd96a67b2015-05-05 14:09:05 -07001920 bounds.outset(halfWidth, halfWidth);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001921 }
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001922
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001923 isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
commit-bot@chromium.orgcefde6e2013-08-30 16:34:52 +00001924
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001925 // The radii are outset for two reasons. First, it allows the shader to simply perform
bsalomonce1c8862014-12-15 07:11:22 -08001926 // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
1927 // Second, the outer radius is used to compute the verts of the bounding box that is
1928 // rendered and the outset ensures the box will cover all partially covered by the rrect
1929 // corners.
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001930 outerRadius += SK_ScalarHalf;
1931 innerRadius -= SK_ScalarHalf;
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001932
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001933 // Expand the rect so all the pixels will be captured.
joshualittd96a67b2015-05-05 14:09:05 -07001934 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001935
joshualitt76e7fb62015-02-11 08:52:27 -08001936 RRectCircleRendererBatch::Geometry geometry;
1937 geometry.fViewMatrix = viewMatrix;
1938 geometry.fColor = color;
1939 geometry.fInnerRadius = innerRadius;
1940 geometry.fOuterRadius = outerRadius;
1941 geometry.fStroke = isStrokeOnly;
joshualittd96a67b2015-05-05 14:09:05 -07001942 geometry.fDevBounds = bounds;
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001943
bsalomoned0bcad2015-05-04 10:36:42 -07001944 return RRectCircleRendererBatch::Create(geometry);
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001945 // otherwise we use the ellipse renderer
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001946 } else {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001947 SkScalar innerXRadius = 0.0f;
1948 SkScalar innerYRadius = 0.0f;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001949 if (hasStroke) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001950 if (SkScalarNearlyZero(scaledStroke.length())) {
1951 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1952 } else {
1953 scaledStroke.scale(SK_ScalarHalf);
1954 }
1955
1956 // we only handle thick strokes for near-circular ellipses
skia.committer@gmail.com8be02fc2013-05-17 07:01:11 +00001957 if (scaledStroke.length() > SK_ScalarHalf &&
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001958 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001959 return nullptr;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001960 }
1961
1962 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1963 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
1964 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
halcanary96fcdcc2015-08-27 07:41:13 -07001965 return nullptr;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001966 }
1967
1968 // this is legit only if scale & translation (which should be the case at the moment)
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001969 if (isStrokeOnly) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001970 innerXRadius = xRadius - scaledStroke.fX;
1971 innerYRadius = yRadius - scaledStroke.fY;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001972 }
1973
1974 xRadius += scaledStroke.fX;
1975 yRadius += scaledStroke.fY;
joshualittd96a67b2015-05-05 14:09:05 -07001976 bounds.outset(scaledStroke.fX, scaledStroke.fY);
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001977 }
jvanverth@google.come3647412013-05-08 15:31:43 +00001978
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001979 isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
commit-bot@chromium.orgcefde6e2013-08-30 16:34:52 +00001980
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001981 // Expand the rect so all the pixels will be captured.
joshualittd96a67b2015-05-05 14:09:05 -07001982 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001983
joshualitt76e7fb62015-02-11 08:52:27 -08001984 RRectEllipseRendererBatch::Geometry geometry;
1985 geometry.fViewMatrix = viewMatrix;
1986 geometry.fColor = color;
1987 geometry.fXRadius = xRadius;
1988 geometry.fYRadius = yRadius;
1989 geometry.fInnerXRadius = innerXRadius;
1990 geometry.fInnerYRadius = innerYRadius;
1991 geometry.fStroke = isStrokeOnly;
joshualittd96a67b2015-05-05 14:09:05 -07001992 geometry.fDevBounds = bounds;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001993
bsalomoned0bcad2015-05-04 10:36:42 -07001994 return RRectEllipseRendererBatch::Create(geometry);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001995 }
joshualitt3e708c52015-04-30 13:49:27 -07001996}
1997
robertphillipsea461502015-05-26 11:38:03 -07001998bool GrOvalRenderer::DrawRRect(GrDrawTarget* target,
joshualittae3d63a2015-07-13 08:44:06 -07001999 const GrPipelineBuilder& pipelineBuilder,
joshualitt3e708c52015-04-30 13:49:27 -07002000 GrColor color,
2001 const SkMatrix& viewMatrix,
2002 bool useAA,
2003 const SkRRect& rrect,
2004 const SkStrokeRec& stroke) {
2005 if (rrect.isOval()) {
robertphillipsea461502015-05-26 11:38:03 -07002006 return DrawOval(target, pipelineBuilder, color, viewMatrix, useAA, rrect.getBounds(),
2007 stroke);
joshualitt3e708c52015-04-30 13:49:27 -07002008 }
2009
joshualittae3d63a2015-07-13 08:44:06 -07002010 bool useCoverageAA = useAA && !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
joshualitt3e708c52015-04-30 13:49:27 -07002011
2012 // only anti-aliased rrects for now
2013 if (!useCoverageAA) {
2014 return false;
2015 }
2016
2017 if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
2018 return false;
2019 }
2020
bsalomonabd30f52015-08-13 13:34:48 -07002021 SkAutoTUnref<GrDrawBatch> batch(create_rrect_batch(color, viewMatrix, rrect, stroke));
joshualitt3e708c52015-04-30 13:49:27 -07002022 if (!batch) {
2023 return false;
2024 }
2025
joshualittae3d63a2015-07-13 08:44:06 -07002026 target->drawBatch(pipelineBuilder, batch);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002027 return true;
2028}
joshualitt3e708c52015-04-30 13:49:27 -07002029
2030///////////////////////////////////////////////////////////////////////////////////////////////////
2031
2032#ifdef GR_TEST_UTILS
2033
bsalomonabd30f52015-08-13 13:34:48 -07002034DRAW_BATCH_TEST_DEFINE(CircleBatch) {
joshualitt3e708c52015-04-30 13:49:27 -07002035 SkMatrix viewMatrix = GrTest::TestMatrix(random);
2036 GrColor color = GrRandomColor(random);
2037 bool useCoverageAA = random->nextBool();
joshualitt6c891102015-05-13 08:51:49 -07002038 SkRect circle = GrTest::TestSquare(random);
joshualitt21279c72015-05-11 07:21:37 -07002039 return create_circle_batch(color, viewMatrix, useCoverageAA, circle,
2040 GrTest::TestStrokeRec(random));
joshualitt3e708c52015-04-30 13:49:27 -07002041}
2042
bsalomonabd30f52015-08-13 13:34:48 -07002043DRAW_BATCH_TEST_DEFINE(EllipseBatch) {
joshualitt3e708c52015-04-30 13:49:27 -07002044 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
2045 GrColor color = GrRandomColor(random);
joshualitt6c891102015-05-13 08:51:49 -07002046 SkRect ellipse = GrTest::TestSquare(random);
2047 return create_ellipse_batch(color, viewMatrix, true, ellipse,
joshualitt21279c72015-05-11 07:21:37 -07002048 GrTest::TestStrokeRec(random));
joshualitt3e708c52015-04-30 13:49:27 -07002049}
2050
bsalomonabd30f52015-08-13 13:34:48 -07002051DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) {
joshualitt3e708c52015-04-30 13:49:27 -07002052 SkMatrix viewMatrix = GrTest::TestMatrix(random);
2053 GrColor color = GrRandomColor(random);
2054 bool useCoverageAA = random->nextBool();
joshualitt6c891102015-05-13 08:51:49 -07002055 SkRect ellipse = GrTest::TestSquare(random);
joshualitt3e708c52015-04-30 13:49:27 -07002056 return create_diellipse_batch(color, viewMatrix, useCoverageAA, ellipse,
joshualitt21279c72015-05-11 07:21:37 -07002057 GrTest::TestStrokeRec(random));
joshualitt3e708c52015-04-30 13:49:27 -07002058}
2059
bsalomonabd30f52015-08-13 13:34:48 -07002060DRAW_BATCH_TEST_DEFINE(RRectBatch) {
joshualitt3e708c52015-04-30 13:49:27 -07002061 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
2062 GrColor color = GrRandomColor(random);
2063 const SkRRect& rrect = GrTest::TestRRectSimple(random);
joshualitt21279c72015-05-11 07:21:37 -07002064 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(random));
joshualitt3e708c52015-04-30 13:49:27 -07002065}
2066
2067#endif