blob: 1fb214a260ed432a0e1824e2e576f79b6e5fb310 [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"
joshualitteb2a6762014-12-04 11:35:33 -080012#include "GrGeometryProcessor.h"
egdaniel605dd0f2014-11-12 08:35:25 -080013#include "GrInvariantOutput.h"
joshualitt76e7fb62015-02-11 08:52:27 -080014#include "GrProcessor.h"
bsalomoned0bcad2015-05-04 10:36:42 -070015#include "GrResourceProvider.h"
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +000016#include "SkRRect.h"
commit-bot@chromium.org81312832013-03-22 18:34:09 +000017#include "SkStrokeRec.h"
bsalomon16b99132015-08-13 14:55:50 -070018#include "batches/GrVertexBatch.h"
egdaniel2d721d32015-11-11 13:06:05 -080019#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniele659a582015-11-13 09:55:43 -080020#include "glsl/GrGLSLGeometryProcessor.h"
egdaniel018fb622015-10-28 07:26:40 -070021#include "glsl/GrGLSLProgramDataManager.h"
egdaniel0eafe792015-11-20 14:01:22 -080022#include "glsl/GrGLSLVarying.h"
egdaniel2d721d32015-11-11 13:06:05 -080023#include "glsl/GrGLSLVertexShaderBuilder.h"
egdaniel7ea439b2015-12-03 09:20:44 -080024#include "glsl/GrGLSLUniformHandler.h"
egdaniel64c47282015-11-13 06:54:19 -080025#include "glsl/GrGLSLUtil.h"
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000026
joshualitt76e7fb62015-02-11 08:52:27 -080027// TODO(joshualitt) - Break this file up during GrBatch post implementation cleanup
28
commit-bot@chromium.org81312832013-03-22 18:34:09 +000029namespace {
brianosmanbb2ff942016-02-11 14:15:18 -080030
commit-bot@chromium.org81312832013-03-22 18:34:09 +000031struct CircleVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000032 SkPoint fPos;
brianosmanbb2ff942016-02-11 14:15:18 -080033 GrColor fColor;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000034 SkPoint fOffset;
commit-bot@chromium.org81312832013-03-22 18:34:09 +000035 SkScalar fOuterRadius;
36 SkScalar fInnerRadius;
37};
38
39struct EllipseVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000040 SkPoint fPos;
brianosmanbb2ff942016-02-11 14:15:18 -080041 GrColor fColor;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000042 SkPoint fOffset;
43 SkPoint fOuterRadii;
44 SkPoint fInnerRadii;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +000045};
46
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +000047struct DIEllipseVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000048 SkPoint fPos;
brianosmanbb2ff942016-02-11 14:15:18 -080049 GrColor fColor;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000050 SkPoint fOuterOffset;
51 SkPoint fInnerOffset;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +000052};
53
commit-bot@chromium.org81312832013-03-22 18:34:09 +000054inline bool circle_stays_circle(const SkMatrix& m) {
55 return m.isSimilarity();
56}
57
58}
59
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000060///////////////////////////////////////////////////////////////////////////////
61
62/**
bsalomonce1c8862014-12-15 07:11:22 -080063 * The output of this effect is a modulation of the input color and coverage for a circle. It
64 * operates in a space normalized by the circle radius (outer radius in the case of a stroke)
65 * with origin at the circle center. Two vertex attributes are used:
66 * vec2f : position in device space of the bounding geometry vertices
67 * vec4f : (p.xy, outerRad, innerRad)
68 * p is the position in the normalized space.
69 * outerRad is the outerRadius in device space.
70 * innerRad is the innerRadius in normalized space (ignored if not stroking).
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000071 */
72
joshualitt249af152014-09-15 11:41:13 -070073class CircleEdgeEffect : public GrGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000074public:
joshualittb8c241a2015-05-19 08:23:30 -070075 static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix,
76 bool usesLocalCoords) {
halcanary385fe4d2015-08-26 13:07:48 -070077 return new CircleEdgeEffect(color, stroke, localMatrix, usesLocalCoords);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000078 }
79
joshualitt71c92602015-01-14 08:12:47 -080080 const Attribute* inPosition() const { return fInPosition; }
brianosmanbb2ff942016-02-11 14:15:18 -080081 const Attribute* inColor() const { return fInColor; }
joshualitt71c92602015-01-14 08:12:47 -080082 const Attribute* inCircleEdge() const { return fInCircleEdge; }
joshualitt88c23fc2015-05-13 14:18:07 -070083 GrColor color() const { return fColor; }
joshualittb8c241a2015-05-19 08:23:30 -070084 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
joshualitte3ababe2015-05-15 07:56:07 -070085 const SkMatrix& localMatrix() const { return fLocalMatrix; }
joshualittb8c241a2015-05-19 08:23:30 -070086 bool usesLocalCoords() const { return fUsesLocalCoords; }
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000087 virtual ~CircleEdgeEffect() {}
88
mtklein36352bf2015-03-25 18:17:31 -070089 const char* name() const override { return "CircleEdge"; }
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000090
91 inline bool isStroked() const { return fStroke; }
92
egdaniel57d3b032015-11-13 11:57:27 -080093 class GLSLProcessor : public GrGLSLGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000094 public:
brianosmanbb2ff942016-02-11 14:15:18 -080095 GLSLProcessor() {}
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000096
mtklein36352bf2015-03-25 18:17:31 -070097 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
joshualitt2dd1ae02014-12-03 06:24:10 -080098 const CircleEdgeEffect& ce = args.fGP.cast<CircleEdgeEffect>();
egdaniel4ca2e602015-11-18 08:01:26 -080099 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -0800100 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -0800101 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
joshualitt2dd1ae02014-12-03 06:24:10 -0800102
joshualittabb52a12015-01-13 15:02:10 -0800103 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -0800104 varyingHandler->emitAttributes(ce);
joshualittabb52a12015-01-13 15:02:10 -0800105
egdaniel8dcdedc2015-11-11 06:27:20 -0800106 GrGLSLVertToFrag v(kVec4f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800107 varyingHandler->addVarying("CircleEdge", &v);
egdaniel4ca2e602015-11-18 08:01:26 -0800108 vertBuilder->codeAppendf("%s = %s;", v.vsOut(), ce.inCircleEdge()->fName);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000109
cdalton85285412016-02-18 12:37:07 -0800110 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualittb8c241a2015-05-19 08:23:30 -0700111 // setup pass through color
112 if (!ce.colorIgnored()) {
brianosmanbb2ff942016-02-11 14:15:18 -0800113 varyingHandler->addPassThroughAttribute(ce.inColor(), args.fOutputColor);
joshualittb8c241a2015-05-19 08:23:30 -0700114 }
joshualitt9b989322014-12-15 14:16:27 -0800115
joshualittabb52a12015-01-13 15:02:10 -0800116 // Setup position
egdaniel7ea439b2015-12-03 09:20:44 -0800117 this->setupPosition(vertBuilder, gpArgs, ce.inPosition()->fName);
joshualittabb52a12015-01-13 15:02:10 -0800118
119 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -0800120 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -0800121 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -0800122 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800123 gpArgs->fPositionVar,
124 ce.inPosition()->fName,
125 ce.localMatrix(),
126 args.fTransformsIn,
127 args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800128
egdaniel4ca2e602015-11-18 08:01:26 -0800129 fragBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn());
130 fragBuilder->codeAppendf("float edgeAlpha = clamp(%s.z * (1.0 - d), 0.0, 1.0);",
131 v.fsIn());
joshualitt2dd1ae02014-12-03 06:24:10 -0800132 if (ce.isStroked()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800133 fragBuilder->codeAppendf("float innerAlpha = clamp(%s.z * (d - %s.w), 0.0, 1.0);",
134 v.fsIn(), v.fsIn());
135 fragBuilder->codeAppend("edgeAlpha *= innerAlpha;");
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000136 }
commit-bot@chromium.org0a6cb602013-04-11 15:05:37 +0000137
egdaniel4ca2e602015-11-18 08:01:26 -0800138 fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000139 }
140
robertphillips46d36f02015-01-18 08:14:14 -0800141 static void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700142 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700143 GrProcessorKeyBuilder* b) {
joshualitte3ababe2015-05-15 07:56:07 -0700144 const CircleEdgeEffect& ce = gp.cast<CircleEdgeEffect>();
145 uint16_t key = ce.isStroked() ? 0x1 : 0x0;
joshualittb8c241a2015-05-19 08:23:30 -0700146 key |= ce.usesLocalCoords() && ce.localMatrix().hasPerspective() ? 0x2 : 0x0;
147 key |= ce.colorIgnored() ? 0x4 : 0x0;
148 b->add32(key);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000149 }
150
egdaniel018fb622015-10-28 07:26:40 -0700151 void setData(const GrGLSLProgramDataManager& pdman,
152 const GrPrimitiveProcessor& gp) override {
joshualitt9b989322014-12-15 14:16:27 -0800153 }
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000154
joshualitte3ababe2015-05-15 07:56:07 -0700155 void setTransformData(const GrPrimitiveProcessor& primProc,
egdaniel018fb622015-10-28 07:26:40 -0700156 const GrGLSLProgramDataManager& pdman,
joshualitte3ababe2015-05-15 07:56:07 -0700157 int index,
158 const SkTArray<const GrCoordTransform*, true>& transforms) override {
159 this->setTransformDataHelper<CircleEdgeEffect>(primProc, pdman, index, transforms);
160 }
161
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000162 private:
egdaniele659a582015-11-13 09:55:43 -0800163 typedef GrGLSLGeometryProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000164 };
165
egdaniel57d3b032015-11-13 11:57:27 -0800166 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
167 GLSLProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800168 }
169
egdaniel57d3b032015-11-13 11:57:27 -0800170 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
171 return new GLSLProcessor();
joshualitteb2a6762014-12-04 11:35:33 -0800172 }
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000173
174private:
joshualittb8c241a2015-05-19 08:23:30 -0700175 CircleEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix, bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700176 : fColor(color)
joshualittb8c241a2015-05-19 08:23:30 -0700177 , fLocalMatrix(localMatrix)
178 , fUsesLocalCoords(usesLocalCoords) {
joshualitteb2a6762014-12-04 11:35:33 -0800179 this->initClassID<CircleEdgeEffect>();
senorblancof2539d52015-05-20 14:03:42 -0700180 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
181 kHigh_GrSLPrecision));
brianosmanbb2ff942016-02-11 14:15:18 -0800182 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800183 fInCircleEdge = &this->addVertexAttrib(Attribute("inCircleEdge",
joshualitt2dd1ae02014-12-03 06:24:10 -0800184 kVec4f_GrVertexAttribType));
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000185 fStroke = stroke;
186 }
187
joshualitt88c23fc2015-05-13 14:18:07 -0700188 GrColor fColor;
joshualitte3ababe2015-05-15 07:56:07 -0700189 SkMatrix fLocalMatrix;
joshualitt71c92602015-01-14 08:12:47 -0800190 const Attribute* fInPosition;
brianosmanbb2ff942016-02-11 14:15:18 -0800191 const Attribute* fInColor;
joshualitt71c92602015-01-14 08:12:47 -0800192 const Attribute* fInCircleEdge;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000193 bool fStroke;
joshualittb8c241a2015-05-19 08:23:30 -0700194 bool fUsesLocalCoords;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000195
joshualittb0a8a372014-09-23 09:50:21 -0700196 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000197
joshualitt249af152014-09-15 11:41:13 -0700198 typedef GrGeometryProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000199};
200
joshualittb0a8a372014-09-23 09:50:21 -0700201GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleEdgeEffect);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000202
bsalomonc21b09e2015-08-28 18:46:56 -0700203const GrGeometryProcessor* CircleEdgeEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700204 return CircleEdgeEffect::Create(GrRandomColor(d->fRandom),
205 d->fRandom->nextBool(),
206 GrTest::TestMatrix(d->fRandom),
207 d->fRandom->nextBool());
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000208}
209
210///////////////////////////////////////////////////////////////////////////////
211
212/**
213 * 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 +0000214 * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii,
215 * in both x and y directions.
216 *
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +0000217 * 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 +0000218 */
219
joshualitt249af152014-09-15 11:41:13 -0700220class EllipseEdgeEffect : public GrGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000221public:
joshualittb8c241a2015-05-19 08:23:30 -0700222 static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix,
223 bool usesLocalCoords) {
halcanary385fe4d2015-08-26 13:07:48 -0700224 return new EllipseEdgeEffect(color, stroke, localMatrix, usesLocalCoords);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000225 }
226
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000227 virtual ~EllipseEdgeEffect() {}
228
mtklein36352bf2015-03-25 18:17:31 -0700229 const char* name() const override { return "EllipseEdge"; }
joshualitt2dd1ae02014-12-03 06:24:10 -0800230
joshualitt71c92602015-01-14 08:12:47 -0800231 const Attribute* inPosition() const { return fInPosition; }
brianosmanbb2ff942016-02-11 14:15:18 -0800232 const Attribute* inColor() const { return fInColor; }
joshualitt71c92602015-01-14 08:12:47 -0800233 const Attribute* inEllipseOffset() const { return fInEllipseOffset; }
234 const Attribute* inEllipseRadii() const { return fInEllipseRadii; }
joshualitt88c23fc2015-05-13 14:18:07 -0700235 GrColor color() const { return fColor; }
joshualittb8c241a2015-05-19 08:23:30 -0700236 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
joshualitte3ababe2015-05-15 07:56:07 -0700237 const SkMatrix& localMatrix() const { return fLocalMatrix; }
joshualittb8c241a2015-05-19 08:23:30 -0700238 bool usesLocalCoords() const { return fUsesLocalCoords; }
joshualitt249af152014-09-15 11:41:13 -0700239
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000240 inline bool isStroked() const { return fStroke; }
241
egdaniel57d3b032015-11-13 11:57:27 -0800242 class GLSLProcessor : public GrGLSLGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000243 public:
brianosmanbb2ff942016-02-11 14:15:18 -0800244 GLSLProcessor() {}
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000245
mtklein36352bf2015-03-25 18:17:31 -0700246 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
joshualitt2dd1ae02014-12-03 06:24:10 -0800247 const EllipseEdgeEffect& ee = args.fGP.cast<EllipseEdgeEffect>();
egdaniel4ca2e602015-11-18 08:01:26 -0800248 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -0800249 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -0800250 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000251
joshualittabb52a12015-01-13 15:02:10 -0800252 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -0800253 varyingHandler->emitAttributes(ee);
joshualittabb52a12015-01-13 15:02:10 -0800254
egdaniel8dcdedc2015-11-11 06:27:20 -0800255 GrGLSLVertToFrag ellipseOffsets(kVec2f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800256 varyingHandler->addVarying("EllipseOffsets", &ellipseOffsets);
egdaniel4ca2e602015-11-18 08:01:26 -0800257 vertBuilder->codeAppendf("%s = %s;", ellipseOffsets.vsOut(),
joshualitt2dd1ae02014-12-03 06:24:10 -0800258 ee.inEllipseOffset()->fName);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000259
egdaniel8dcdedc2015-11-11 06:27:20 -0800260 GrGLSLVertToFrag ellipseRadii(kVec4f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800261 varyingHandler->addVarying("EllipseRadii", &ellipseRadii);
egdaniel4ca2e602015-11-18 08:01:26 -0800262 vertBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(),
joshualitt2dd1ae02014-12-03 06:24:10 -0800263 ee.inEllipseRadii()->fName);
264
cdalton85285412016-02-18 12:37:07 -0800265 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualittb8c241a2015-05-19 08:23:30 -0700266 // setup pass through color
267 if (!ee.colorIgnored()) {
brianosmanbb2ff942016-02-11 14:15:18 -0800268 varyingHandler->addPassThroughAttribute(ee.inColor(), args.fOutputColor);
joshualittb8c241a2015-05-19 08:23:30 -0700269 }
joshualitt9b989322014-12-15 14:16:27 -0800270
joshualittabb52a12015-01-13 15:02:10 -0800271 // Setup position
egdaniel7ea439b2015-12-03 09:20:44 -0800272 this->setupPosition(vertBuilder, gpArgs, ee.inPosition()->fName);
joshualittabb52a12015-01-13 15:02:10 -0800273
274 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -0800275 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -0800276 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -0800277 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800278 gpArgs->fPositionVar,
279 ee.inPosition()->fName,
280 ee.localMatrix(),
281 args.fTransformsIn,
282 args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800283
skia.committer@gmail.com8be02fc2013-05-17 07:01:11 +0000284 // for outer curve
egdaniel4ca2e602015-11-18 08:01:26 -0800285 fragBuilder->codeAppendf("vec2 scaledOffset = %s*%s.xy;", ellipseOffsets.fsIn(),
286 ellipseRadii.fsIn());
287 fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
288 fragBuilder->codeAppendf("vec2 grad = 2.0*scaledOffset*%s.xy;", ellipseRadii.fsIn());
289 fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
joshualitt74077b92014-10-24 11:26:03 -0700290
commit-bot@chromium.org1b035d82014-04-09 17:11:09 +0000291 // avoid calling inversesqrt on zero.
egdaniel4ca2e602015-11-18 08:01:26 -0800292 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
293 fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
brianosmanc6052ac2016-02-12 10:20:00 -0800294 fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000295
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +0000296 // for inner curve
joshualitt2dd1ae02014-12-03 06:24:10 -0800297 if (ee.isStroked()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800298 fragBuilder->codeAppendf("scaledOffset = %s*%s.zw;",
299 ellipseOffsets.fsIn(), ellipseRadii.fsIn());
300 fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
301 fragBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;",
302 ellipseRadii.fsIn());
303 fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
304 fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000305 }
306
egdaniel4ca2e602015-11-18 08:01:26 -0800307 fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000308 }
309
robertphillips46d36f02015-01-18 08:14:14 -0800310 static void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700311 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700312 GrProcessorKeyBuilder* b) {
joshualitte3ababe2015-05-15 07:56:07 -0700313 const EllipseEdgeEffect& ee = gp.cast<EllipseEdgeEffect>();
314 uint16_t key = ee.isStroked() ? 0x1 : 0x0;
joshualittb8c241a2015-05-19 08:23:30 -0700315 key |= ee.usesLocalCoords() && ee.localMatrix().hasPerspective() ? 0x2 : 0x0;
316 key |= ee.colorIgnored() ? 0x4 : 0x0;
317 b->add32(key);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000318 }
319
egdaniel018fb622015-10-28 07:26:40 -0700320 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp) override {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000321 }
322
joshualitte3ababe2015-05-15 07:56:07 -0700323 void setTransformData(const GrPrimitiveProcessor& primProc,
egdaniel018fb622015-10-28 07:26:40 -0700324 const GrGLSLProgramDataManager& pdman,
joshualitte3ababe2015-05-15 07:56:07 -0700325 int index,
326 const SkTArray<const GrCoordTransform*, true>& transforms) override {
327 this->setTransformDataHelper<EllipseEdgeEffect>(primProc, pdman, index, transforms);
328 }
329
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000330 private:
egdaniele659a582015-11-13 09:55:43 -0800331 typedef GrGLSLGeometryProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000332 };
333
egdaniel57d3b032015-11-13 11:57:27 -0800334 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
335 GLSLProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800336 }
337
egdaniel57d3b032015-11-13 11:57:27 -0800338 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
339 return new GLSLProcessor();
joshualitteb2a6762014-12-04 11:35:33 -0800340 }
341
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000342private:
joshualittb8c241a2015-05-19 08:23:30 -0700343 EllipseEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix,
344 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700345 : fColor(color)
joshualittb8c241a2015-05-19 08:23:30 -0700346 , fLocalMatrix(localMatrix)
347 , fUsesLocalCoords(usesLocalCoords) {
joshualitteb2a6762014-12-04 11:35:33 -0800348 this->initClassID<EllipseEdgeEffect>();
joshualitt71c92602015-01-14 08:12:47 -0800349 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
brianosmanbb2ff942016-02-11 14:15:18 -0800350 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800351 fInEllipseOffset = &this->addVertexAttrib(Attribute("inEllipseOffset",
joshualitt465283c2015-09-11 08:19:35 -0700352 kVec2f_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800353 fInEllipseRadii = &this->addVertexAttrib(Attribute("inEllipseRadii",
joshualitt465283c2015-09-11 08:19:35 -0700354 kVec4f_GrVertexAttribType));
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000355 fStroke = stroke;
356 }
357
joshualitt71c92602015-01-14 08:12:47 -0800358 const Attribute* fInPosition;
brianosmanbb2ff942016-02-11 14:15:18 -0800359 const Attribute* fInColor;
joshualitt71c92602015-01-14 08:12:47 -0800360 const Attribute* fInEllipseOffset;
361 const Attribute* fInEllipseRadii;
joshualitt88c23fc2015-05-13 14:18:07 -0700362 GrColor fColor;
joshualitte3ababe2015-05-15 07:56:07 -0700363 SkMatrix fLocalMatrix;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000364 bool fStroke;
joshualittb8c241a2015-05-19 08:23:30 -0700365 bool fUsesLocalCoords;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000366
joshualittb0a8a372014-09-23 09:50:21 -0700367 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000368
joshualitt249af152014-09-15 11:41:13 -0700369 typedef GrGeometryProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000370};
371
joshualittb0a8a372014-09-23 09:50:21 -0700372GR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseEdgeEffect);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000373
bsalomonc21b09e2015-08-28 18:46:56 -0700374const GrGeometryProcessor* EllipseEdgeEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700375 return EllipseEdgeEffect::Create(GrRandomColor(d->fRandom),
376 d->fRandom->nextBool(),
377 GrTest::TestMatrix(d->fRandom),
378 d->fRandom->nextBool());
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000379}
380
381///////////////////////////////////////////////////////////////////////////////
382
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000383/**
skia.committer@gmail.com6fc1b492013-09-06 07:01:45 +0000384 * 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 +0000385 * specified as a 2D offset from center for both the outer and inner paths (if stroked). The
386 * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge corrected by
387 * using differentials.
388 *
389 * The result is device-independent and can be used with any affine matrix.
390 */
391
joshualitt249af152014-09-15 11:41:13 -0700392class DIEllipseEdgeEffect : public GrGeometryProcessor {
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000393public:
394 enum Mode { kStroke = 0, kHairline, kFill };
395
joshualittb8c241a2015-05-19 08:23:30 -0700396 static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, Mode mode,
397 bool usesLocalCoords) {
halcanary385fe4d2015-08-26 13:07:48 -0700398 return new DIEllipseEdgeEffect(color, viewMatrix, mode, usesLocalCoords);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000399 }
400
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000401 virtual ~DIEllipseEdgeEffect() {}
402
mtklein36352bf2015-03-25 18:17:31 -0700403 const char* name() const override { return "DIEllipseEdge"; }
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000404
joshualitt71c92602015-01-14 08:12:47 -0800405 const Attribute* inPosition() const { return fInPosition; }
brianosmanbb2ff942016-02-11 14:15:18 -0800406 const Attribute* inColor() const { return fInColor; }
joshualitt71c92602015-01-14 08:12:47 -0800407 const Attribute* inEllipseOffsets0() const { return fInEllipseOffsets0; }
408 const Attribute* inEllipseOffsets1() const { return fInEllipseOffsets1; }
joshualitt88c23fc2015-05-13 14:18:07 -0700409 GrColor color() const { return fColor; }
joshualittb8c241a2015-05-19 08:23:30 -0700410 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
joshualitte578a952015-05-14 10:09:13 -0700411 const SkMatrix& viewMatrix() const { return fViewMatrix; }
joshualittb8c241a2015-05-19 08:23:30 -0700412 bool usesLocalCoords() const { return fUsesLocalCoords; }
joshualitt249af152014-09-15 11:41:13 -0700413
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000414 inline Mode getMode() const { return fMode; }
415
egdaniel57d3b032015-11-13 11:57:27 -0800416 class GLSLProcessor : public GrGLSLGeometryProcessor {
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000417 public:
egdaniel57d3b032015-11-13 11:57:27 -0800418 GLSLProcessor()
brianosmanbb2ff942016-02-11 14:15:18 -0800419 : fViewMatrix(SkMatrix::InvalidMatrix()) {}
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000420
joshualitt465283c2015-09-11 08:19:35 -0700421 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
joshualitt2dd1ae02014-12-03 06:24:10 -0800422 const DIEllipseEdgeEffect& ee = args.fGP.cast<DIEllipseEdgeEffect>();
egdaniel4ca2e602015-11-18 08:01:26 -0800423 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -0800424 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -0800425 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000426
joshualittabb52a12015-01-13 15:02:10 -0800427 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -0800428 varyingHandler->emitAttributes(ee);
joshualittabb52a12015-01-13 15:02:10 -0800429
egdaniel8dcdedc2015-11-11 06:27:20 -0800430 GrGLSLVertToFrag offsets0(kVec2f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800431 varyingHandler->addVarying("EllipseOffsets0", &offsets0);
egdaniel4ca2e602015-11-18 08:01:26 -0800432 vertBuilder->codeAppendf("%s = %s;", offsets0.vsOut(),
joshualitt2dd1ae02014-12-03 06:24:10 -0800433 ee.inEllipseOffsets0()->fName);
joshualitt74077b92014-10-24 11:26:03 -0700434
egdaniel8dcdedc2015-11-11 06:27:20 -0800435 GrGLSLVertToFrag offsets1(kVec2f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800436 varyingHandler->addVarying("EllipseOffsets1", &offsets1);
egdaniel4ca2e602015-11-18 08:01:26 -0800437 vertBuilder->codeAppendf("%s = %s;", offsets1.vsOut(),
joshualitt2dd1ae02014-12-03 06:24:10 -0800438 ee.inEllipseOffsets1()->fName);
439
cdalton85285412016-02-18 12:37:07 -0800440 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualittb8c241a2015-05-19 08:23:30 -0700441 // setup pass through color
442 if (!ee.colorIgnored()) {
brianosmanbb2ff942016-02-11 14:15:18 -0800443 varyingHandler->addPassThroughAttribute(ee.inColor(), args.fOutputColor);
joshualittb8c241a2015-05-19 08:23:30 -0700444 }
joshualitt9b989322014-12-15 14:16:27 -0800445
joshualittabb52a12015-01-13 15:02:10 -0800446 // Setup position
egdaniel7ea439b2015-12-03 09:20:44 -0800447 this->setupPosition(vertBuilder,
448 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800449 gpArgs,
450 ee.inPosition()->fName,
451 ee.viewMatrix(),
joshualitt5559ca22015-05-21 15:50:36 -0700452 &fViewMatrixUniform);
joshualittabb52a12015-01-13 15:02:10 -0800453
454 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -0800455 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -0800456 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -0800457 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800458 gpArgs->fPositionVar,
459 ee.inPosition()->fName,
460 args.fTransformsIn,
461 args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800462
egdaniel4ca2e602015-11-18 08:01:26 -0800463 SkAssertResult(fragBuilder->enableFeature(
egdaniel2d721d32015-11-11 13:06:05 -0800464 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000465 // for outer curve
egdaniel4ca2e602015-11-18 08:01:26 -0800466 fragBuilder->codeAppendf("vec2 scaledOffset = %s.xy;", offsets0.fsIn());
467 fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
468 fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s);", offsets0.fsIn());
469 fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s);", offsets0.fsIn());
470 fragBuilder->codeAppendf("vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
471 " 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
472 offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn());
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000473
egdaniel4ca2e602015-11-18 08:01:26 -0800474 fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
commit-bot@chromium.org1b035d82014-04-09 17:11:09 +0000475 // avoid calling inversesqrt on zero.
egdaniel4ca2e602015-11-18 08:01:26 -0800476 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
477 fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
joshualitt2dd1ae02014-12-03 06:24:10 -0800478 if (kHairline == ee.getMode()) {
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000479 // can probably do this with one step
egdaniel4ca2e602015-11-18 08:01:26 -0800480 fragBuilder->codeAppend("float edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);");
481 fragBuilder->codeAppend("edgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);");
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000482 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800483 fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000484 }
485
486 // for inner curve
joshualitt2dd1ae02014-12-03 06:24:10 -0800487 if (kStroke == ee.getMode()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800488 fragBuilder->codeAppendf("scaledOffset = %s.xy;", offsets1.fsIn());
489 fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
490 fragBuilder->codeAppendf("duvdx = dFdx(%s);", offsets1.fsIn());
491 fragBuilder->codeAppendf("duvdy = dFdy(%s);", offsets1.fsIn());
492 fragBuilder->codeAppendf("grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
493 " 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
494 offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(),
495 offsets1.fsIn());
496 fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
497 fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000498 }
499
egdaniel4ca2e602015-11-18 08:01:26 -0800500 fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000501 }
502
robertphillips46d36f02015-01-18 08:14:14 -0800503 static void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700504 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700505 GrProcessorKeyBuilder* b) {
robertphillips46d36f02015-01-18 08:14:14 -0800506 const DIEllipseEdgeEffect& ellipseEffect = gp.cast<DIEllipseEdgeEffect>();
joshualitt8fc6c2d2014-12-22 15:27:05 -0800507 uint16_t key = ellipseEffect.getMode();
joshualittb8c241a2015-05-19 08:23:30 -0700508 key |= ellipseEffect.colorIgnored() << 9;
509 key |= ComputePosKey(ellipseEffect.viewMatrix()) << 10;
510 b->add32(key);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000511 }
512
egdaniel018fb622015-10-28 07:26:40 -0700513 void setData(const GrGLSLProgramDataManager& pdman,
514 const GrPrimitiveProcessor& gp) override {
joshualitte578a952015-05-14 10:09:13 -0700515 const DIEllipseEdgeEffect& dee = gp.cast<DIEllipseEdgeEffect>();
joshualitt5559ca22015-05-21 15:50:36 -0700516
517 if (!dee.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dee.viewMatrix())) {
518 fViewMatrix = dee.viewMatrix();
egdaniel018fb622015-10-28 07:26:40 -0700519 float viewMatrix[3 * 3];
egdaniel64c47282015-11-13 06:54:19 -0800520 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
joshualitt5559ca22015-05-21 15:50:36 -0700521 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
522 }
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000523 }
524
525 private:
joshualitt5559ca22015-05-21 15:50:36 -0700526 SkMatrix fViewMatrix;
joshualitt5559ca22015-05-21 15:50:36 -0700527 UniformHandle fViewMatrixUniform;
joshualitt9b989322014-12-15 14:16:27 -0800528
egdaniele659a582015-11-13 09:55:43 -0800529 typedef GrGLSLGeometryProcessor INHERITED;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000530 };
531
egdaniel57d3b032015-11-13 11:57:27 -0800532 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
533 GLSLProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800534 }
535
egdaniel57d3b032015-11-13 11:57:27 -0800536 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
537 return new GLSLProcessor();
joshualitteb2a6762014-12-04 11:35:33 -0800538 }
539
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000540private:
joshualittb8c241a2015-05-19 08:23:30 -0700541 DIEllipseEdgeEffect(GrColor color, const SkMatrix& viewMatrix, Mode mode,
542 bool usesLocalCoords)
joshualitte578a952015-05-14 10:09:13 -0700543 : fColor(color)
joshualittb8c241a2015-05-19 08:23:30 -0700544 , fViewMatrix(viewMatrix)
545 , fUsesLocalCoords(usesLocalCoords) {
joshualitteb2a6762014-12-04 11:35:33 -0800546 this->initClassID<DIEllipseEdgeEffect>();
senorblancof2539d52015-05-20 14:03:42 -0700547 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
548 kHigh_GrSLPrecision));
brianosmanbb2ff942016-02-11 14:15:18 -0800549 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800550 fInEllipseOffsets0 = &this->addVertexAttrib(Attribute("inEllipseOffsets0",
joshualittb8c241a2015-05-19 08:23:30 -0700551 kVec2f_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800552 fInEllipseOffsets1 = &this->addVertexAttrib(Attribute("inEllipseOffsets1",
joshualittb8c241a2015-05-19 08:23:30 -0700553 kVec2f_GrVertexAttribType));
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000554 fMode = mode;
555 }
556
joshualitt71c92602015-01-14 08:12:47 -0800557 const Attribute* fInPosition;
brianosmanbb2ff942016-02-11 14:15:18 -0800558 const Attribute* fInColor;
joshualitt71c92602015-01-14 08:12:47 -0800559 const Attribute* fInEllipseOffsets0;
560 const Attribute* fInEllipseOffsets1;
joshualitt88c23fc2015-05-13 14:18:07 -0700561 GrColor fColor;
joshualitte578a952015-05-14 10:09:13 -0700562 SkMatrix fViewMatrix;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000563 Mode fMode;
joshualittb8c241a2015-05-19 08:23:30 -0700564 bool fUsesLocalCoords;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000565
joshualittb0a8a372014-09-23 09:50:21 -0700566 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000567
joshualitt249af152014-09-15 11:41:13 -0700568 typedef GrGeometryProcessor INHERITED;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000569};
570
joshualittb0a8a372014-09-23 09:50:21 -0700571GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseEdgeEffect);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000572
bsalomonc21b09e2015-08-28 18:46:56 -0700573const GrGeometryProcessor* DIEllipseEdgeEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700574 return DIEllipseEdgeEffect::Create(GrRandomColor(d->fRandom),
575 GrTest::TestMatrix(d->fRandom),
576 (Mode)(d->fRandom->nextRangeU(0,2)),
577 d->fRandom->nextBool());
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000578}
579
580///////////////////////////////////////////////////////////////////////////////
581
robertphillipsb56f9272016-02-25 11:03:52 -0800582GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color,
robertphillips0cc2f852016-02-24 13:36:56 -0800583 const SkMatrix& viewMatrix,
robertphillips0cc2f852016-02-24 13:36:56 -0800584 const SkRect& oval,
585 const SkStrokeRec& stroke,
586 GrShaderCaps* shaderCaps) {
skia.committer@gmail.com7e328512013-03-23 07:01:28 +0000587 // we can draw circles
joshualitt8059eb92014-12-29 15:10:07 -0800588 if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(viewMatrix)) {
robertphillips0cc2f852016-02-24 13:36:56 -0800589 return CreateCircleBatch(color, viewMatrix, oval, stroke);
590 }
591
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000592 // if we have shader derivative support, render as device-independent
robertphillips0cc2f852016-02-24 13:36:56 -0800593 if (shaderCaps->shaderDerivativeSupport()) {
594 return CreateDIEllipseBatch(color, viewMatrix, oval, stroke);
595 }
596
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +0000597 // otherwise axis-aligned ellipses only
robertphillips0cc2f852016-02-24 13:36:56 -0800598 if (viewMatrix.rectStaysRect()) {
599 return CreateEllipseBatch(color, viewMatrix, oval, stroke);
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000600 }
601
robertphillips0cc2f852016-02-24 13:36:56 -0800602 return nullptr;
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000603}
604
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +0000605///////////////////////////////////////////////////////////////////////////////
606
bsalomonabd30f52015-08-13 13:34:48 -0700607class CircleBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -0800608public:
reed1b55a962015-09-17 20:16:13 -0700609 DEFINE_BATCH_CLASS_ID
610
joshualitt76e7fb62015-02-11 08:52:27 -0800611 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -0800612 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -0700613 SkRect fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -0800614 SkScalar fInnerRadius;
615 SkScalar fOuterRadius;
reed1b55a962015-09-17 20:16:13 -0700616 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -0800617 bool fStroke;
joshualitt76e7fb62015-02-11 08:52:27 -0800618 };
619
halcanary385fe4d2015-08-26 13:07:48 -0700620 static GrDrawBatch* Create(const Geometry& geometry) { return new CircleBatch(geometry); }
joshualitt76e7fb62015-02-11 08:52:27 -0800621
mtklein36352bf2015-03-25 18:17:31 -0700622 const char* name() const override { return "CircleBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -0800623
robertphillipse004bfc2015-11-16 09:06:59 -0800624 SkString dumpInfo() const override {
625 SkString string;
626 for (int i = 0; i < fGeoData.count(); ++i) {
627 string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
628 "InnerRad: %.2f, OuterRad: %.2f\n",
629 fGeoData[i].fColor,
630 fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
631 fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
632 fGeoData[i].fInnerRadius,
633 fGeoData[i].fOuterRadius);
634 }
635 string.append(INHERITED::dumpInfo());
636 return string;
637 }
638
ethannicholasff210322015-11-24 12:10:10 -0800639 void computePipelineOptimizations(GrInitInvariantOutput* color,
640 GrInitInvariantOutput* coverage,
641 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -0800642 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -0800643 color->setKnownFourComponents(fGeoData[0].fColor);
644 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -0800645 }
646
bsalomone46f9fe2015-08-18 06:05:14 -0700647private:
ethannicholasff210322015-11-24 12:10:10 -0800648 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -0800649 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -0800650 if (!overrides.readsColor()) {
joshualitt76e7fb62015-02-11 08:52:27 -0800651 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -0800652 }
ethannicholasff210322015-11-24 12:10:10 -0800653 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -0800654
655 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -0800656 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -0800657 fBatch.fColor = fGeoData[0].fColor;
658 fBatch.fStroke = fGeoData[0].fStroke;
ethannicholasff210322015-11-24 12:10:10 -0800659 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
660 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -0800661 }
662
joshualitt144c3c82015-11-30 12:30:13 -0800663 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -0800664 SkMatrix invert;
665 if (!this->viewMatrix().invert(&invert)) {
666 return;
667 }
668
669 // Setup geometry processor
670 SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
671 this->stroke(),
joshualittb8c241a2015-05-19 08:23:30 -0700672 invert,
673 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -0800674
bsalomon75398562015-08-17 12:55:38 -0700675 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -0800676
joshualitt76e7fb62015-02-11 08:52:27 -0800677 int instanceCount = fGeoData.count();
joshualitt76e7fb62015-02-11 08:52:27 -0800678 size_t vertexStride = gp->getVertexStride();
679 SkASSERT(vertexStride == sizeof(CircleVertex));
bsalomonb5238a72015-05-05 07:49:49 -0700680 QuadHelper helper;
bsalomon75398562015-08-17 12:55:38 -0700681 CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target, vertexStride,
bsalomonb5238a72015-05-05 07:49:49 -0700682 instanceCount));
683 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800684 return;
685 }
686
joshualitt76e7fb62015-02-11 08:52:27 -0800687 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800688 const Geometry& geom = fGeoData[i];
joshualitt76e7fb62015-02-11 08:52:27 -0800689
brianosmanbb2ff942016-02-11 14:15:18 -0800690 GrColor color = geom.fColor;
bsalomonb5238a72015-05-05 07:49:49 -0700691 SkScalar innerRadius = geom.fInnerRadius;
692 SkScalar outerRadius = geom.fOuterRadius;
joshualitt76e7fb62015-02-11 08:52:27 -0800693
bsalomonb5238a72015-05-05 07:49:49 -0700694 const SkRect& bounds = geom.fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -0800695
696 // The inner radius in the vertex data must be specified in normalized space.
697 innerRadius = innerRadius / outerRadius;
698 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -0800699 verts[0].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800700 verts[0].fOffset = SkPoint::Make(-1, -1);
701 verts[0].fOuterRadius = outerRadius;
702 verts[0].fInnerRadius = innerRadius;
703
704 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -0800705 verts[1].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800706 verts[1].fOffset = SkPoint::Make(-1, 1);
707 verts[1].fOuterRadius = outerRadius;
708 verts[1].fInnerRadius = innerRadius;
709
710 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -0800711 verts[2].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800712 verts[2].fOffset = SkPoint::Make(1, 1);
713 verts[2].fOuterRadius = outerRadius;
714 verts[2].fInnerRadius = innerRadius;
715
716 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -0800717 verts[3].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800718 verts[3].fOffset = SkPoint::Make(1, -1);
719 verts[3].fOuterRadius = outerRadius;
720 verts[3].fInnerRadius = innerRadius;
721
bsalomonb5238a72015-05-05 07:49:49 -0700722 verts += kVerticesPerQuad;
joshualitt76e7fb62015-02-11 08:52:27 -0800723 }
bsalomon75398562015-08-17 12:55:38 -0700724 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -0800725 }
726
727 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
728
reed1b55a962015-09-17 20:16:13 -0700729 CircleBatch(const Geometry& geometry) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -0800730 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -0700731
732 this->setBounds(geometry.fDevBounds);
joshualitt76e7fb62015-02-11 08:52:27 -0800733 }
734
bsalomoncb02b382015-08-12 11:14:50 -0700735 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -0700736 CircleBatch* that = t->cast<CircleBatch>();
737 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
738 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -0700739 return false;
740 }
741
joshualitt76e7fb62015-02-11 08:52:27 -0800742 if (this->stroke() != that->stroke()) {
743 return false;
744 }
745
746 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
747 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
748 return false;
749 }
750
751 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -0700752 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -0800753 return true;
754 }
755
756 GrColor color() const { return fBatch.fColor; }
757 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
758 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
759 bool stroke() const { return fBatch.fStroke; }
760
761 struct BatchTracker {
762 GrColor fColor;
763 bool fStroke;
764 bool fUsesLocalCoords;
765 bool fColorIgnored;
766 bool fCoverageIgnored;
767 };
768
joshualitt76e7fb62015-02-11 08:52:27 -0800769 BatchTracker fBatch;
770 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -0700771
772 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -0800773};
774
bsalomonabd30f52015-08-13 13:34:48 -0700775static GrDrawBatch* create_circle_batch(GrColor color,
776 const SkMatrix& viewMatrix,
bsalomonabd30f52015-08-13 13:34:48 -0700777 const SkRect& circle,
778 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000779 SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
joshualitt8059eb92014-12-29 15:10:07 -0800780 viewMatrix.mapPoints(&center, 1);
781 SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
782 SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000783
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000784 SkStrokeRec::Style style = stroke.getStyle();
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000785 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
786 SkStrokeRec::kHairline_Style == style;
787 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
skia.committer@gmail.com7e328512013-03-23 07:01:28 +0000788
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000789 SkScalar innerRadius = 0.0f;
790 SkScalar outerRadius = radius;
791 SkScalar halfWidth = 0;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000792 if (hasStroke) {
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000793 if (SkScalarNearlyZero(strokeWidth)) {
794 halfWidth = SK_ScalarHalf;
795 } else {
796 halfWidth = SkScalarHalf(strokeWidth);
797 }
798
799 outerRadius += halfWidth;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000800 if (isStrokeOnly) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +0000801 innerRadius = radius - halfWidth;
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000802 }
803 }
804
bsalomonce1c8862014-12-15 07:11:22 -0800805 // The radii are outset for two reasons. First, it allows the shader to simply perform simpler
806 // computation because the computed alpha is zero, rather than 50%, at the radius.
807 // Second, the outer radius is used to compute the verts of the bounding box that is rendered
808 // and the outset ensures the box will cover all partially covered by the circle.
bsalomon@google.com58e30fe2013-04-01 19:01:20 +0000809 outerRadius += SK_ScalarHalf;
810 innerRadius -= SK_ScalarHalf;
811
joshualitt76e7fb62015-02-11 08:52:27 -0800812 CircleBatch::Geometry geometry;
813 geometry.fViewMatrix = viewMatrix;
814 geometry.fColor = color;
815 geometry.fInnerRadius = innerRadius;
816 geometry.fOuterRadius = outerRadius;
817 geometry.fStroke = isStrokeOnly && innerRadius > 0;
joshualittd96a67b2015-05-05 14:09:05 -0700818 geometry.fDevBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
819 center.fX + outerRadius, center.fY + outerRadius);
commit-bot@chromium.org0a6cb602013-04-11 15:05:37 +0000820
joshualitt3e708c52015-04-30 13:49:27 -0700821 return CircleBatch::Create(geometry);
822}
823
robertphillips0cc2f852016-02-24 13:36:56 -0800824GrDrawBatch* GrOvalRenderer::CreateCircleBatch(GrColor color,
825 const SkMatrix& viewMatrix,
826 const SkRect& circle,
827 const SkStrokeRec& stroke) {
828 return create_circle_batch(color, viewMatrix, circle, stroke);
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000829}
830
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +0000831///////////////////////////////////////////////////////////////////////////////
832
bsalomonabd30f52015-08-13 13:34:48 -0700833class EllipseBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -0800834public:
reed1b55a962015-09-17 20:16:13 -0700835 DEFINE_BATCH_CLASS_ID
836
joshualitt76e7fb62015-02-11 08:52:27 -0800837 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -0800838 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -0700839 SkRect fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -0800840 SkScalar fXRadius;
841 SkScalar fYRadius;
842 SkScalar fInnerXRadius;
843 SkScalar fInnerYRadius;
reed1b55a962015-09-17 20:16:13 -0700844 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -0800845 bool fStroke;
joshualitt76e7fb62015-02-11 08:52:27 -0800846 };
847
halcanary385fe4d2015-08-26 13:07:48 -0700848 static GrDrawBatch* Create(const Geometry& geometry) { return new EllipseBatch(geometry); }
joshualitt76e7fb62015-02-11 08:52:27 -0800849
mtklein36352bf2015-03-25 18:17:31 -0700850 const char* name() const override { return "EllipseBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -0800851
ethannicholasff210322015-11-24 12:10:10 -0800852 void computePipelineOptimizations(GrInitInvariantOutput* color,
853 GrInitInvariantOutput* coverage,
854 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -0800855 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -0800856 color->setKnownFourComponents(fGeoData[0].fColor);
857 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -0800858 }
859
bsalomone46f9fe2015-08-18 06:05:14 -0700860private:
ethannicholasff210322015-11-24 12:10:10 -0800861 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -0800862 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -0800863 if (!overrides.readsCoverage()) {
joshualitt76e7fb62015-02-11 08:52:27 -0800864 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -0800865 }
ethannicholasff210322015-11-24 12:10:10 -0800866 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -0800867
868 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -0800869 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -0800870 fBatch.fColor = fGeoData[0].fColor;
871 fBatch.fStroke = fGeoData[0].fStroke;
ethannicholasff210322015-11-24 12:10:10 -0800872 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
873 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -0800874 }
875
joshualitt144c3c82015-11-30 12:30:13 -0800876 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -0800877 SkMatrix invert;
878 if (!this->viewMatrix().invert(&invert)) {
879 return;
880 }
881
882 // Setup geometry processor
883 SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
884 this->stroke(),
joshualittb8c241a2015-05-19 08:23:30 -0700885 invert,
886 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -0800887
bsalomon75398562015-08-17 12:55:38 -0700888 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -0800889
joshualitt76e7fb62015-02-11 08:52:27 -0800890 int instanceCount = fGeoData.count();
bsalomonb5238a72015-05-05 07:49:49 -0700891 QuadHelper helper;
joshualitt76e7fb62015-02-11 08:52:27 -0800892 size_t vertexStride = gp->getVertexStride();
joshualitt19e00582015-02-11 17:36:30 -0800893 SkASSERT(vertexStride == sizeof(EllipseVertex));
bsalomonb5238a72015-05-05 07:49:49 -0700894 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
bsalomon75398562015-08-17 12:55:38 -0700895 helper.init(target, vertexStride, instanceCount));
bsalomonb5238a72015-05-05 07:49:49 -0700896 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800897 return;
898 }
899
bsalomon8415abe2015-05-04 11:41:41 -0700900 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800901 const Geometry& geom = fGeoData[i];
bsalomon8415abe2015-05-04 11:41:41 -0700902
brianosmanbb2ff942016-02-11 14:15:18 -0800903 GrColor color = geom.fColor;
bsalomonb5238a72015-05-05 07:49:49 -0700904 SkScalar xRadius = geom.fXRadius;
905 SkScalar yRadius = geom.fYRadius;
joshualitt76e7fb62015-02-11 08:52:27 -0800906
907 // Compute the reciprocals of the radii here to save time in the shader
908 SkScalar xRadRecip = SkScalarInvert(xRadius);
909 SkScalar yRadRecip = SkScalarInvert(yRadius);
bsalomonb5238a72015-05-05 07:49:49 -0700910 SkScalar xInnerRadRecip = SkScalarInvert(geom.fInnerXRadius);
911 SkScalar yInnerRadRecip = SkScalarInvert(geom.fInnerYRadius);
joshualitt76e7fb62015-02-11 08:52:27 -0800912
bsalomonb5238a72015-05-05 07:49:49 -0700913 const SkRect& bounds = geom.fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -0800914
915 // The inner radius in the vertex data must be specified in normalized space.
916 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -0800917 verts[0].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800918 verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
919 verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
920 verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
921
922 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -0800923 verts[1].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800924 verts[1].fOffset = SkPoint::Make(-xRadius, yRadius);
925 verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
926 verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
927
928 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -0800929 verts[2].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800930 verts[2].fOffset = SkPoint::Make(xRadius, yRadius);
931 verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
932 verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
933
934 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -0800935 verts[3].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -0800936 verts[3].fOffset = SkPoint::Make(xRadius, -yRadius);
937 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
938 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
939
bsalomonb5238a72015-05-05 07:49:49 -0700940 verts += kVerticesPerQuad;
joshualitt76e7fb62015-02-11 08:52:27 -0800941 }
bsalomon75398562015-08-17 12:55:38 -0700942 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -0800943 }
944
945 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
946
reed1b55a962015-09-17 20:16:13 -0700947 EllipseBatch(const Geometry& geometry) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -0800948 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -0700949
950 this->setBounds(geometry.fDevBounds);
joshualitt76e7fb62015-02-11 08:52:27 -0800951 }
952
bsalomoncb02b382015-08-12 11:14:50 -0700953 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -0700954 EllipseBatch* that = t->cast<EllipseBatch>();
955
956 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
957 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -0700958 return false;
959 }
960
joshualitt76e7fb62015-02-11 08:52:27 -0800961 if (this->stroke() != that->stroke()) {
962 return false;
963 }
964
965 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
966 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
967 return false;
968 }
969
970 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -0700971 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -0800972 return true;
973 }
974
975 GrColor color() const { return fBatch.fColor; }
976 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
977 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
978 bool stroke() const { return fBatch.fStroke; }
979
980 struct BatchTracker {
981 GrColor fColor;
982 bool fStroke;
983 bool fUsesLocalCoords;
984 bool fColorIgnored;
985 bool fCoverageIgnored;
986 };
987
joshualitt76e7fb62015-02-11 08:52:27 -0800988 BatchTracker fBatch;
989 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -0700990
991 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -0800992};
993
bsalomonabd30f52015-08-13 13:34:48 -0700994static GrDrawBatch* create_ellipse_batch(GrColor color,
995 const SkMatrix& viewMatrix,
bsalomonabd30f52015-08-13 13:34:48 -0700996 const SkRect& ellipse,
997 const SkStrokeRec& stroke) {
robertphillips0cc2f852016-02-24 13:36:56 -0800998 SkASSERT(viewMatrix.rectStaysRect());
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000999
commit-bot@chromium.org0c888282013-04-19 19:01:45 +00001000 // do any matrix crunching before we reset the draw state for device coords
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +00001001 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
joshualitt8059eb92014-12-29 15:10:07 -08001002 viewMatrix.mapPoints(&center, 1);
commit-bot@chromium.org0c888282013-04-19 19:01:45 +00001003 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
1004 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
joshualitt8059eb92014-12-29 15:10:07 -08001005 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius +
1006 viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius);
1007 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius +
1008 viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius);
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001009
commit-bot@chromium.org0c888282013-04-19 19:01:45 +00001010 // do (potentially) anisotropic mapping of stroke
1011 SkVector scaledStroke;
1012 SkScalar strokeWidth = stroke.getWidth();
joshualitt8059eb92014-12-29 15:10:07 -08001013 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
1014 viewMatrix[SkMatrix::kMSkewY]));
1015 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
1016 viewMatrix[SkMatrix::kMScaleY]));
commit-bot@chromium.org0c888282013-04-19 19:01:45 +00001017
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001018 SkStrokeRec::Style style = stroke.getStyle();
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001019 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1020 SkStrokeRec::kHairline_Style == style;
1021 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001022
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001023 SkScalar innerXRadius = 0;
1024 SkScalar innerYRadius = 0;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001025 if (hasStroke) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001026 if (SkScalarNearlyZero(scaledStroke.length())) {
1027 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1028 } else {
1029 scaledStroke.scale(SK_ScalarHalf);
1030 }
1031
1032 // we only handle thick strokes for near-circular ellipses
1033 if (scaledStroke.length() > SK_ScalarHalf &&
1034 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001035 return nullptr;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001036 }
1037
1038 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1039 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
1040 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
halcanary96fcdcc2015-08-27 07:41:13 -07001041 return nullptr;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001042 }
1043
1044 // this is legit only if scale & translation (which should be the case at the moment)
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001045 if (isStrokeOnly) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001046 innerXRadius = xRadius - scaledStroke.fX;
1047 innerYRadius = yRadius - scaledStroke.fY;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001048 }
1049
1050 xRadius += scaledStroke.fX;
1051 yRadius += scaledStroke.fY;
1052 }
1053
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001054 // We've extended the outer x radius out half a pixel to antialias.
commit-bot@chromium.org0a6cb602013-04-11 15:05:37 +00001055 // This will also expand the rect so all the pixels will be captured.
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001056 // TODO: Consider if we should use sqrt(2)/2 instead
brianosmanbd6366a2016-02-14 10:33:03 -08001057 xRadius += SK_ScalarHalf;
1058 yRadius += SK_ScalarHalf;
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001059
joshualitt76e7fb62015-02-11 08:52:27 -08001060 EllipseBatch::Geometry geometry;
1061 geometry.fViewMatrix = viewMatrix;
1062 geometry.fColor = color;
1063 geometry.fXRadius = xRadius;
1064 geometry.fYRadius = yRadius;
1065 geometry.fInnerXRadius = innerXRadius;
1066 geometry.fInnerYRadius = innerYRadius;
1067 geometry.fStroke = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
brianosmanbd6366a2016-02-14 10:33:03 -08001068 geometry.fDevBounds = SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius,
1069 center.fX + xRadius, center.fY + yRadius);
commit-bot@chromium.org0a6cb602013-04-11 15:05:37 +00001070
joshualitt3e708c52015-04-30 13:49:27 -07001071 return EllipseBatch::Create(geometry);
1072}
1073
robertphillips0cc2f852016-02-24 13:36:56 -08001074GrDrawBatch* GrOvalRenderer::CreateEllipseBatch(GrColor color,
1075 const SkMatrix& viewMatrix,
1076 const SkRect& ellipse,
1077 const SkStrokeRec& stroke) {
1078 return create_ellipse_batch(color, viewMatrix, ellipse, stroke);
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001079}
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001080
joshualitt76e7fb62015-02-11 08:52:27 -08001081/////////////////////////////////////////////////////////////////////////////////////////////////
1082
bsalomonabd30f52015-08-13 13:34:48 -07001083class DIEllipseBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -08001084public:
reed1b55a962015-09-17 20:16:13 -07001085 DEFINE_BATCH_CLASS_ID
1086
joshualitt76e7fb62015-02-11 08:52:27 -08001087 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -08001088 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -07001089 SkRect fBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001090 SkScalar fXRadius;
1091 SkScalar fYRadius;
1092 SkScalar fInnerXRadius;
1093 SkScalar fInnerYRadius;
1094 SkScalar fGeoDx;
1095 SkScalar fGeoDy;
reed1b55a962015-09-17 20:16:13 -07001096 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -08001097 DIEllipseEdgeEffect::Mode fMode;
joshualitt76e7fb62015-02-11 08:52:27 -08001098 };
1099
bsalomonabd30f52015-08-13 13:34:48 -07001100 static GrDrawBatch* Create(const Geometry& geometry, const SkRect& bounds) {
halcanary385fe4d2015-08-26 13:07:48 -07001101 return new DIEllipseBatch(geometry, bounds);
joshualitt76e7fb62015-02-11 08:52:27 -08001102 }
1103
mtklein36352bf2015-03-25 18:17:31 -07001104 const char* name() const override { return "DIEllipseBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -08001105
ethannicholasff210322015-11-24 12:10:10 -08001106 void computePipelineOptimizations(GrInitInvariantOutput* color,
1107 GrInitInvariantOutput* coverage,
1108 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001109 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -08001110 color->setKnownFourComponents(fGeoData[0].fColor);
1111 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -08001112 }
1113
bsalomone46f9fe2015-08-18 06:05:14 -07001114private:
1115
ethannicholasff210322015-11-24 12:10:10 -08001116 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -08001117 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -08001118 if (!overrides.readsColor()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001119 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -08001120 }
ethannicholasff210322015-11-24 12:10:10 -08001121 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -08001122
1123 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -08001124 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -08001125 fBatch.fColor = fGeoData[0].fColor;
1126 fBatch.fMode = fGeoData[0].fMode;
ethannicholasff210322015-11-24 12:10:10 -08001127 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
1128 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -08001129 }
1130
joshualitt144c3c82015-11-30 12:30:13 -08001131 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001132 // Setup geometry processor
1133 SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(this->color(),
1134 this->viewMatrix(),
joshualittb8c241a2015-05-19 08:23:30 -07001135 this->mode(),
1136 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -08001137
bsalomon75398562015-08-17 12:55:38 -07001138 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -08001139
joshualitt76e7fb62015-02-11 08:52:27 -08001140 int instanceCount = fGeoData.count();
joshualitt76e7fb62015-02-11 08:52:27 -08001141 size_t vertexStride = gp->getVertexStride();
joshualitt19e00582015-02-11 17:36:30 -08001142 SkASSERT(vertexStride == sizeof(DIEllipseVertex));
bsalomonb5238a72015-05-05 07:49:49 -07001143 QuadHelper helper;
1144 DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(
bsalomon75398562015-08-17 12:55:38 -07001145 helper.init(target, vertexStride, instanceCount));
bsalomonb5238a72015-05-05 07:49:49 -07001146 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -08001147 return;
1148 }
1149
joshualitt76e7fb62015-02-11 08:52:27 -08001150 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -08001151 const Geometry& geom = fGeoData[i];
joshualitt76e7fb62015-02-11 08:52:27 -08001152
brianosmanbb2ff942016-02-11 14:15:18 -08001153 GrColor color = geom.fColor;
bsalomonb5238a72015-05-05 07:49:49 -07001154 SkScalar xRadius = geom.fXRadius;
1155 SkScalar yRadius = geom.fYRadius;
joshualitt76e7fb62015-02-11 08:52:27 -08001156
bsalomonb5238a72015-05-05 07:49:49 -07001157 const SkRect& bounds = geom.fBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001158
1159 // This adjusts the "radius" to include the half-pixel border
reed80ea19c2015-05-12 10:37:34 -07001160 SkScalar offsetDx = geom.fGeoDx / xRadius;
1161 SkScalar offsetDy = geom.fGeoDy / yRadius;
joshualitt76e7fb62015-02-11 08:52:27 -08001162
reed80ea19c2015-05-12 10:37:34 -07001163 SkScalar innerRatioX = xRadius / geom.fInnerXRadius;
1164 SkScalar innerRatioY = yRadius / geom.fInnerYRadius;
joshualitt76e7fb62015-02-11 08:52:27 -08001165
1166 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -08001167 verts[0].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001168 verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
1169 verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
1170
1171 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -08001172 verts[1].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001173 verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
1174 verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
1175
1176 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
brianosmanbb2ff942016-02-11 14:15:18 -08001177 verts[2].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001178 verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
1179 verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
1180
1181 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
brianosmanbb2ff942016-02-11 14:15:18 -08001182 verts[3].fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001183 verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
1184 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
1185
bsalomonb5238a72015-05-05 07:49:49 -07001186 verts += kVerticesPerQuad;
joshualitt76e7fb62015-02-11 08:52:27 -08001187 }
bsalomon75398562015-08-17 12:55:38 -07001188 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -08001189 }
1190
1191 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1192
reed1b55a962015-09-17 20:16:13 -07001193 DIEllipseBatch(const Geometry& geometry, const SkRect& bounds) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001194 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -07001195
1196 this->setBounds(bounds);
joshualitt76e7fb62015-02-11 08:52:27 -08001197 }
1198
bsalomoncb02b382015-08-12 11:14:50 -07001199 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -07001200 DIEllipseBatch* that = t->cast<DIEllipseBatch>();
1201 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1202 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -07001203 return false;
1204 }
1205
joshualitt76e7fb62015-02-11 08:52:27 -08001206 if (this->mode() != that->mode()) {
1207 return false;
1208 }
1209
joshualittd96a67b2015-05-05 14:09:05 -07001210 // TODO rewrite to allow positioning on CPU
1211 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
joshualitt76e7fb62015-02-11 08:52:27 -08001212 return false;
1213 }
1214
1215 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -07001216 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -08001217 return true;
1218 }
1219
1220 GrColor color() const { return fBatch.fColor; }
1221 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1222 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1223 DIEllipseEdgeEffect::Mode mode() const { return fBatch.fMode; }
1224
1225 struct BatchTracker {
1226 GrColor fColor;
1227 DIEllipseEdgeEffect::Mode fMode;
1228 bool fUsesLocalCoords;
1229 bool fColorIgnored;
1230 bool fCoverageIgnored;
1231 };
1232
joshualitt76e7fb62015-02-11 08:52:27 -08001233 BatchTracker fBatch;
1234 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -07001235
1236 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -08001237};
1238
bsalomonabd30f52015-08-13 13:34:48 -07001239static GrDrawBatch* create_diellipse_batch(GrColor color,
1240 const SkMatrix& viewMatrix,
bsalomonabd30f52015-08-13 13:34:48 -07001241 const SkRect& ellipse,
1242 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +00001243 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001244 SkScalar xRadius = SkScalarHalf(ellipse.width());
skia.committer@gmail.com6fc1b492013-09-06 07:01:45 +00001245 SkScalar yRadius = SkScalarHalf(ellipse.height());
1246
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001247 SkStrokeRec::Style style = stroke.getStyle();
skia.committer@gmail.com6fc1b492013-09-06 07:01:45 +00001248 DIEllipseEdgeEffect::Mode mode = (SkStrokeRec::kStroke_Style == style) ?
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001249 DIEllipseEdgeEffect::kStroke :
skia.committer@gmail.com6fc1b492013-09-06 07:01:45 +00001250 (SkStrokeRec::kHairline_Style == style) ?
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001251 DIEllipseEdgeEffect::kHairline : DIEllipseEdgeEffect::kFill;
1252
1253 SkScalar innerXRadius = 0;
1254 SkScalar innerYRadius = 0;
1255 if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
1256 SkScalar strokeWidth = stroke.getWidth();
1257
1258 if (SkScalarNearlyZero(strokeWidth)) {
1259 strokeWidth = SK_ScalarHalf;
1260 } else {
1261 strokeWidth *= SK_ScalarHalf;
1262 }
1263
1264 // we only handle thick strokes for near-circular ellipses
1265 if (strokeWidth > SK_ScalarHalf &&
1266 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001267 return nullptr;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001268 }
1269
1270 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1271 if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
1272 strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
halcanary96fcdcc2015-08-27 07:41:13 -07001273 return nullptr;
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001274 }
1275
1276 // set inner radius (if needed)
1277 if (SkStrokeRec::kStroke_Style == style) {
1278 innerXRadius = xRadius - strokeWidth;
1279 innerYRadius = yRadius - strokeWidth;
1280 }
1281
1282 xRadius += strokeWidth;
1283 yRadius += strokeWidth;
1284 }
1285 if (DIEllipseEdgeEffect::kStroke == mode) {
1286 mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kStroke :
1287 DIEllipseEdgeEffect::kFill;
1288 }
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001289
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001290 // This expands the outer rect so that after CTM we end up with a half-pixel border
joshualitt8059eb92014-12-29 15:10:07 -08001291 SkScalar a = viewMatrix[SkMatrix::kMScaleX];
1292 SkScalar b = viewMatrix[SkMatrix::kMSkewX];
1293 SkScalar c = viewMatrix[SkMatrix::kMSkewY];
1294 SkScalar d = viewMatrix[SkMatrix::kMScaleY];
reed80ea19c2015-05-12 10:37:34 -07001295 SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
1296 SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001297
joshualitt76e7fb62015-02-11 08:52:27 -08001298 DIEllipseBatch::Geometry geometry;
1299 geometry.fViewMatrix = viewMatrix;
1300 geometry.fColor = color;
1301 geometry.fXRadius = xRadius;
1302 geometry.fYRadius = yRadius;
1303 geometry.fInnerXRadius = innerXRadius;
1304 geometry.fInnerYRadius = innerYRadius;
1305 geometry.fGeoDx = geoDx;
1306 geometry.fGeoDy = geoDy;
1307 geometry.fMode = mode;
joshualittd96a67b2015-05-05 14:09:05 -07001308 geometry.fBounds = SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
1309 center.fX + xRadius + geoDx, center.fY + yRadius + geoDy);
egdaniel9ef1bb12015-04-20 12:28:57 -07001310
joshualittd96a67b2015-05-05 14:09:05 -07001311 SkRect devBounds = geometry.fBounds;
1312 viewMatrix.mapRect(&devBounds);
1313 return DIEllipseBatch::Create(geometry, devBounds);
joshualitt3e708c52015-04-30 13:49:27 -07001314}
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001315
robertphillips0cc2f852016-02-24 13:36:56 -08001316GrDrawBatch* GrOvalRenderer::CreateDIEllipseBatch(GrColor color,
1317 const SkMatrix& viewMatrix,
1318 const SkRect& ellipse,
1319 const SkStrokeRec& stroke) {
1320 return create_diellipse_batch(color, viewMatrix, ellipse, stroke);
commit-bot@chromium.org5242ed72013-09-05 19:26:51 +00001321}
1322
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001323///////////////////////////////////////////////////////////////////////////////
1324
1325static const uint16_t gRRectIndices[] = {
1326 // corners
1327 0, 1, 5, 0, 5, 4,
1328 2, 3, 7, 2, 7, 6,
1329 8, 9, 13, 8, 13, 12,
1330 10, 11, 15, 10, 15, 14,
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001331
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001332 // edges
1333 1, 2, 6, 1, 6, 5,
1334 4, 5, 9, 4, 9, 8,
1335 6, 7, 11, 6, 11, 10,
1336 9, 10, 14, 9, 14, 13,
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001337
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001338 // center
1339 // we place this at the end so that we can ignore these indices when rendering stroke-only
1340 5, 6, 10, 5, 10, 9
1341};
1342
joshualitt5ead6da2014-10-22 16:00:29 -07001343static const int kIndicesPerStrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
1344static const int kIndicesPerRRect = SK_ARRAY_COUNT(gRRectIndices);
1345static const int kVertsPerRRect = 16;
1346static const int kNumRRectsInIndexBuffer = 256;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001347
bsalomoned0bcad2015-05-04 10:36:42 -07001348GR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1349GR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1350static const GrIndexBuffer* ref_rrect_index_buffer(bool strokeOnly,
1351 GrResourceProvider* resourceProvider) {
1352 GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1353 GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1354 if (strokeOnly) {
bsalomoneae62002015-07-31 13:59:30 -07001355 return resourceProvider->findOrCreateInstancedIndexBuffer(
bsalomoned0bcad2015-05-04 10:36:42 -07001356 gRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1357 gStrokeRRectOnlyIndexBufferKey);
1358 } else {
bsalomoneae62002015-07-31 13:59:30 -07001359 return resourceProvider->findOrCreateInstancedIndexBuffer(
bsalomoned0bcad2015-05-04 10:36:42 -07001360 gRRectIndices, kIndicesPerRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1361 gRRectOnlyIndexBufferKey);
1362
1363 }
1364}
1365
joshualitt76e7fb62015-02-11 08:52:27 -08001366///////////////////////////////////////////////////////////////////////////////////////////////////
1367
bsalomonabd30f52015-08-13 13:34:48 -07001368class RRectCircleRendererBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -08001369public:
reed1b55a962015-09-17 20:16:13 -07001370 DEFINE_BATCH_CLASS_ID
1371
joshualitt76e7fb62015-02-11 08:52:27 -08001372 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -08001373 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -07001374 SkRect fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001375 SkScalar fInnerRadius;
1376 SkScalar fOuterRadius;
reed1b55a962015-09-17 20:16:13 -07001377 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -08001378 bool fStroke;
joshualitt76e7fb62015-02-11 08:52:27 -08001379 };
1380
bsalomonabd30f52015-08-13 13:34:48 -07001381 static GrDrawBatch* Create(const Geometry& geometry) {
halcanary385fe4d2015-08-26 13:07:48 -07001382 return new RRectCircleRendererBatch(geometry);
joshualitt76e7fb62015-02-11 08:52:27 -08001383 }
1384
mtklein36352bf2015-03-25 18:17:31 -07001385 const char* name() const override { return "RRectCircleBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -08001386
ethannicholasff210322015-11-24 12:10:10 -08001387 void computePipelineOptimizations(GrInitInvariantOutput* color,
1388 GrInitInvariantOutput* coverage,
1389 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001390 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -08001391 color->setKnownFourComponents(fGeoData[0].fColor);
1392 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -08001393 }
1394
bsalomone46f9fe2015-08-18 06:05:14 -07001395private:
ethannicholasff210322015-11-24 12:10:10 -08001396 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -08001397 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -08001398 if (!overrides.readsColor()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001399 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -08001400 }
ethannicholasff210322015-11-24 12:10:10 -08001401 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -08001402
1403 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -08001404 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -08001405 fBatch.fColor = fGeoData[0].fColor;
1406 fBatch.fStroke = fGeoData[0].fStroke;
ethannicholasff210322015-11-24 12:10:10 -08001407 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
1408 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -08001409 }
1410
joshualitt144c3c82015-11-30 12:30:13 -08001411 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001412 // reset to device coordinates
1413 SkMatrix invert;
1414 if (!this->viewMatrix().invert(&invert)) {
1415 SkDebugf("Failed to invert\n");
1416 return;
1417 }
1418
1419 // Setup geometry processor
1420 SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
1421 this->stroke(),
joshualittb8c241a2015-05-19 08:23:30 -07001422 invert,
1423 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -08001424
bsalomon75398562015-08-17 12:55:38 -07001425 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -08001426
joshualitt76e7fb62015-02-11 08:52:27 -08001427 int instanceCount = fGeoData.count();
joshualitt76e7fb62015-02-11 08:52:27 -08001428 size_t vertexStride = gp->getVertexStride();
1429 SkASSERT(vertexStride == sizeof(CircleVertex));
1430
bsalomonb5238a72015-05-05 07:49:49 -07001431 // drop out the middle quad if we're stroked
1432 int indicesPerInstance = this->stroke() ? kIndicesPerStrokeRRect : kIndicesPerRRect;
bsalomoned0bcad2015-05-04 10:36:42 -07001433 SkAutoTUnref<const GrIndexBuffer> indexBuffer(
bsalomon75398562015-08-17 12:55:38 -07001434 ref_rrect_index_buffer(this->stroke(), target->resourceProvider()));
joshualitt76e7fb62015-02-11 08:52:27 -08001435
bsalomonb5238a72015-05-05 07:49:49 -07001436 InstancedHelper helper;
bsalomon75398562015-08-17 12:55:38 -07001437 CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target,
bsalomonb5238a72015-05-05 07:49:49 -07001438 kTriangles_GrPrimitiveType, vertexStride, indexBuffer, kVertsPerRRect,
1439 indicesPerInstance, instanceCount));
1440 if (!verts || !indexBuffer) {
joshualitt4b31de82015-03-05 14:33:41 -08001441 SkDebugf("Could not allocate vertices\n");
1442 return;
1443 }
1444
joshualitt76e7fb62015-02-11 08:52:27 -08001445 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -08001446 const Geometry& args = fGeoData[i];
joshualitt76e7fb62015-02-11 08:52:27 -08001447
brianosmanbb2ff942016-02-11 14:15:18 -08001448 GrColor color = args.fColor;
joshualitt76e7fb62015-02-11 08:52:27 -08001449 SkScalar outerRadius = args.fOuterRadius;
1450
egdanielbc227142015-04-21 06:28:08 -07001451 const SkRect& bounds = args.fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001452
1453 SkScalar yCoords[4] = {
1454 bounds.fTop,
1455 bounds.fTop + outerRadius,
1456 bounds.fBottom - outerRadius,
1457 bounds.fBottom
1458 };
1459
1460 SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
1461 // The inner radius in the vertex data must be specified in normalized space.
1462 SkScalar innerRadius = args.fInnerRadius / args.fOuterRadius;
1463 for (int i = 0; i < 4; ++i) {
1464 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001465 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001466 verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
1467 verts->fOuterRadius = outerRadius;
1468 verts->fInnerRadius = innerRadius;
1469 verts++;
1470
1471 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001472 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001473 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1474 verts->fOuterRadius = outerRadius;
1475 verts->fInnerRadius = innerRadius;
1476 verts++;
1477
1478 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001479 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001480 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1481 verts->fOuterRadius = outerRadius;
1482 verts->fInnerRadius = innerRadius;
1483 verts++;
1484
1485 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001486 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001487 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
1488 verts->fOuterRadius = outerRadius;
1489 verts->fInnerRadius = innerRadius;
1490 verts++;
1491 }
1492 }
1493
bsalomon75398562015-08-17 12:55:38 -07001494 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -08001495 }
1496
1497 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1498
reed1b55a962015-09-17 20:16:13 -07001499 RRectCircleRendererBatch(const Geometry& geometry) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001500 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -07001501
1502 this->setBounds(geometry.fDevBounds);
joshualitt76e7fb62015-02-11 08:52:27 -08001503 }
1504
bsalomoncb02b382015-08-12 11:14:50 -07001505 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -07001506 RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>();
1507 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1508 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -07001509 return false;
1510 }
1511
joshualitt76e7fb62015-02-11 08:52:27 -08001512 if (this->stroke() != that->stroke()) {
1513 return false;
1514 }
1515
1516 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1517 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1518 return false;
1519 }
1520
1521 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -07001522 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -08001523 return true;
1524 }
1525
1526 GrColor color() const { return fBatch.fColor; }
1527 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1528 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1529 bool stroke() const { return fBatch.fStroke; }
1530
1531 struct BatchTracker {
1532 GrColor fColor;
1533 bool fStroke;
1534 bool fUsesLocalCoords;
1535 bool fColorIgnored;
1536 bool fCoverageIgnored;
1537 };
1538
joshualitt76e7fb62015-02-11 08:52:27 -08001539 BatchTracker fBatch;
1540 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -07001541
1542 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -08001543};
1544
bsalomonabd30f52015-08-13 13:34:48 -07001545class RRectEllipseRendererBatch : public GrVertexBatch {
joshualitt76e7fb62015-02-11 08:52:27 -08001546public:
reed1b55a962015-09-17 20:16:13 -07001547 DEFINE_BATCH_CLASS_ID
1548
joshualitt76e7fb62015-02-11 08:52:27 -08001549 struct Geometry {
joshualitt76e7fb62015-02-11 08:52:27 -08001550 SkMatrix fViewMatrix;
reed1b55a962015-09-17 20:16:13 -07001551 SkRect fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001552 SkScalar fXRadius;
1553 SkScalar fYRadius;
1554 SkScalar fInnerXRadius;
1555 SkScalar fInnerYRadius;
reed1b55a962015-09-17 20:16:13 -07001556 GrColor fColor;
joshualitt76e7fb62015-02-11 08:52:27 -08001557 bool fStroke;
joshualitt76e7fb62015-02-11 08:52:27 -08001558 };
1559
bsalomonabd30f52015-08-13 13:34:48 -07001560 static GrDrawBatch* Create(const Geometry& geometry) {
halcanary385fe4d2015-08-26 13:07:48 -07001561 return new RRectEllipseRendererBatch(geometry);
joshualitt76e7fb62015-02-11 08:52:27 -08001562 }
1563
mtklein36352bf2015-03-25 18:17:31 -07001564 const char* name() const override { return "RRectEllipseRendererBatch"; }
joshualitt76e7fb62015-02-11 08:52:27 -08001565
ethannicholasff210322015-11-24 12:10:10 -08001566 void computePipelineOptimizations(GrInitInvariantOutput* color,
1567 GrInitInvariantOutput* coverage,
1568 GrBatchToXPOverrides* overrides) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001569 // When this is called on a batch, there is only one geometry bundle
ethannicholasff210322015-11-24 12:10:10 -08001570 color->setKnownFourComponents(fGeoData[0].fColor);
1571 coverage->setUnknownSingleComponent();
joshualitt76e7fb62015-02-11 08:52:27 -08001572 }
1573
bsalomone46f9fe2015-08-18 06:05:14 -07001574private:
ethannicholasff210322015-11-24 12:10:10 -08001575 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt76e7fb62015-02-11 08:52:27 -08001576 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -08001577 if (!overrides.readsColor()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001578 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt76e7fb62015-02-11 08:52:27 -08001579 }
ethannicholasff210322015-11-24 12:10:10 -08001580 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt76e7fb62015-02-11 08:52:27 -08001581
1582 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -08001583 fBatch.fColorIgnored = !overrides.readsColor();
joshualitt76e7fb62015-02-11 08:52:27 -08001584 fBatch.fColor = fGeoData[0].fColor;
1585 fBatch.fStroke = fGeoData[0].fStroke;
ethannicholasff210322015-11-24 12:10:10 -08001586 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
1587 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt76e7fb62015-02-11 08:52:27 -08001588 }
1589
joshualitt144c3c82015-11-30 12:30:13 -08001590 void onPrepareDraws(Target* target) const override {
joshualitt76e7fb62015-02-11 08:52:27 -08001591 // reset to device coordinates
1592 SkMatrix invert;
1593 if (!this->viewMatrix().invert(&invert)) {
1594 SkDebugf("Failed to invert\n");
1595 return;
1596 }
1597
1598 // Setup geometry processor
1599 SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
1600 this->stroke(),
joshualittb8c241a2015-05-19 08:23:30 -07001601 invert,
1602 this->usesLocalCoords()));
joshualitt76e7fb62015-02-11 08:52:27 -08001603
bsalomon75398562015-08-17 12:55:38 -07001604 target->initDraw(gp, this->pipeline());
joshualitt76e7fb62015-02-11 08:52:27 -08001605
joshualitt76e7fb62015-02-11 08:52:27 -08001606 int instanceCount = fGeoData.count();
joshualitt76e7fb62015-02-11 08:52:27 -08001607 size_t vertexStride = gp->getVertexStride();
1608 SkASSERT(vertexStride == sizeof(EllipseVertex));
1609
bsalomonb5238a72015-05-05 07:49:49 -07001610 // drop out the middle quad if we're stroked
1611 int indicesPerInstance = this->stroke() ? kIndicesPerStrokeRRect : kIndicesPerRRect;
bsalomoned0bcad2015-05-04 10:36:42 -07001612 SkAutoTUnref<const GrIndexBuffer> indexBuffer(
bsalomon75398562015-08-17 12:55:38 -07001613 ref_rrect_index_buffer(this->stroke(), target->resourceProvider()));
joshualitt76e7fb62015-02-11 08:52:27 -08001614
bsalomonb5238a72015-05-05 07:49:49 -07001615 InstancedHelper helper;
1616 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
bsalomon75398562015-08-17 12:55:38 -07001617 helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer,
bsalomonb5238a72015-05-05 07:49:49 -07001618 kVertsPerRRect, indicesPerInstance, instanceCount));
1619 if (!verts || !indexBuffer) {
joshualitt4b31de82015-03-05 14:33:41 -08001620 SkDebugf("Could not allocate vertices\n");
1621 return;
1622 }
1623
joshualitt76e7fb62015-02-11 08:52:27 -08001624 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -08001625 const Geometry& args = fGeoData[i];
joshualitt76e7fb62015-02-11 08:52:27 -08001626
brianosmanbb2ff942016-02-11 14:15:18 -08001627 GrColor color = args.fColor;
1628
joshualitt76e7fb62015-02-11 08:52:27 -08001629 // Compute the reciprocals of the radii here to save time in the shader
1630 SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
1631 SkScalar yRadRecip = SkScalarInvert(args.fYRadius);
1632 SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
1633 SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
1634
1635 // Extend the radii out half a pixel to antialias.
1636 SkScalar xOuterRadius = args.fXRadius + SK_ScalarHalf;
1637 SkScalar yOuterRadius = args.fYRadius + SK_ScalarHalf;
1638
egdanielbc227142015-04-21 06:28:08 -07001639 const SkRect& bounds = args.fDevBounds;
joshualitt76e7fb62015-02-11 08:52:27 -08001640
1641 SkScalar yCoords[4] = {
1642 bounds.fTop,
1643 bounds.fTop + yOuterRadius,
1644 bounds.fBottom - yOuterRadius,
1645 bounds.fBottom
1646 };
1647 SkScalar yOuterOffsets[4] = {
1648 yOuterRadius,
1649 SK_ScalarNearlyZero, // we're using inversesqrt() in shader, so can't be exactly 0
1650 SK_ScalarNearlyZero,
1651 yOuterRadius
1652 };
1653
1654 for (int i = 0; i < 4; ++i) {
1655 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001656 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001657 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1658 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1659 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1660 verts++;
1661
1662 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001663 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001664 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
1665 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1666 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1667 verts++;
1668
1669 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001670 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001671 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
1672 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1673 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1674 verts++;
1675
1676 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
brianosmanbb2ff942016-02-11 14:15:18 -08001677 verts->fColor = color;
joshualitt76e7fb62015-02-11 08:52:27 -08001678 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1679 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1680 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1681 verts++;
1682 }
1683 }
bsalomon75398562015-08-17 12:55:38 -07001684 helper.recordDraw(target);
joshualitt76e7fb62015-02-11 08:52:27 -08001685 }
1686
1687 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1688
reed1b55a962015-09-17 20:16:13 -07001689 RRectEllipseRendererBatch(const Geometry& geometry) : INHERITED(ClassID()) {
joshualitt76e7fb62015-02-11 08:52:27 -08001690 fGeoData.push_back(geometry);
joshualitt99c7c072015-05-01 13:43:30 -07001691
1692 this->setBounds(geometry.fDevBounds);
joshualitt76e7fb62015-02-11 08:52:27 -08001693 }
1694
bsalomoncb02b382015-08-12 11:14:50 -07001695 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -07001696 RRectEllipseRendererBatch* that = t->cast<RRectEllipseRendererBatch>();
1697
1698 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1699 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -07001700 return false;
1701 }
1702
joshualitt76e7fb62015-02-11 08:52:27 -08001703 if (this->stroke() != that->stroke()) {
1704 return false;
1705 }
1706
1707 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1708 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1709 return false;
1710 }
1711
1712 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -07001713 this->joinBounds(that->bounds());
joshualitt76e7fb62015-02-11 08:52:27 -08001714 return true;
1715 }
1716
1717 GrColor color() const { return fBatch.fColor; }
1718 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1719 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1720 bool stroke() const { return fBatch.fStroke; }
1721
1722 struct BatchTracker {
1723 GrColor fColor;
1724 bool fStroke;
1725 bool fUsesLocalCoords;
1726 bool fColorIgnored;
1727 bool fCoverageIgnored;
1728 };
1729
joshualitt76e7fb62015-02-11 08:52:27 -08001730 BatchTracker fBatch;
1731 SkSTArray<1, Geometry, true> fGeoData;
reed1b55a962015-09-17 20:16:13 -07001732
1733 typedef GrVertexBatch INHERITED;
joshualitt76e7fb62015-02-11 08:52:27 -08001734};
1735
bsalomonabd30f52015-08-13 13:34:48 -07001736static GrDrawBatch* create_rrect_batch(GrColor color,
1737 const SkMatrix& viewMatrix,
1738 const SkRRect& rrect,
1739 const SkStrokeRec& stroke) {
joshualitt3e708c52015-04-30 13:49:27 -07001740 SkASSERT(viewMatrix.rectStaysRect());
1741 SkASSERT(rrect.isSimple());
1742 SkASSERT(!rrect.isOval());
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001743
joshualitt3e708c52015-04-30 13:49:27 -07001744 // RRect batchs only handle simple, but not too simple, rrects
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001745 // do any matrix crunching before we reset the draw state for device coords
1746 const SkRect& rrectBounds = rrect.getBounds();
joshualittd96a67b2015-05-05 14:09:05 -07001747 SkRect bounds;
1748 viewMatrix.mapRect(&bounds, rrectBounds);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001749
1750 SkVector radii = rrect.getSimpleRadii();
joshualitt8059eb92014-12-29 15:10:07 -08001751 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX +
1752 viewMatrix[SkMatrix::kMSkewY]*radii.fY);
1753 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX +
1754 viewMatrix[SkMatrix::kMScaleY]*radii.fY);
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001755
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001756 SkStrokeRec::Style style = stroke.getStyle();
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001757
1758 // do (potentially) anisotropic mapping of stroke
1759 SkVector scaledStroke;
1760 SkScalar strokeWidth = stroke.getWidth();
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001761
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001762 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1763 SkStrokeRec::kHairline_Style == style;
1764 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
1765
1766 if (hasStroke) {
1767 if (SkStrokeRec::kHairline_Style == style) {
1768 scaledStroke.set(1, 1);
1769 } else {
joshualitt8059eb92014-12-29 15:10:07 -08001770 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
1771 viewMatrix[SkMatrix::kMSkewY]));
1772 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
1773 viewMatrix[SkMatrix::kMScaleY]));
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001774 }
1775
1776 // if half of strokewidth is greater than radius, we don't handle that right now
1777 if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) {
halcanary96fcdcc2015-08-27 07:41:13 -07001778 return nullptr;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001779 }
1780 }
1781
1782 // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
1783 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
1784 // patch will have fractional coverage. This only matters when the interior is actually filled.
1785 // We could consider falling back to rect rendering here, since a tiny radius is
1786 // indistinguishable from a square corner.
1787 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001788 return nullptr;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001789 }
1790
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001791 // if the corners are circles, use the circle renderer
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001792 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001793 SkScalar innerRadius = 0.0f;
1794 SkScalar outerRadius = xRadius;
1795 SkScalar halfWidth = 0;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001796 if (hasStroke) {
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001797 if (SkScalarNearlyZero(scaledStroke.fX)) {
1798 halfWidth = SK_ScalarHalf;
1799 } else {
1800 halfWidth = SkScalarHalf(scaledStroke.fX);
1801 }
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001802
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001803 if (isStrokeOnly) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001804 innerRadius = xRadius - halfWidth;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001805 }
1806 outerRadius += halfWidth;
joshualittd96a67b2015-05-05 14:09:05 -07001807 bounds.outset(halfWidth, halfWidth);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001808 }
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001809
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001810 isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
commit-bot@chromium.orgcefde6e2013-08-30 16:34:52 +00001811
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001812 // The radii are outset for two reasons. First, it allows the shader to simply perform
bsalomonce1c8862014-12-15 07:11:22 -08001813 // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
1814 // Second, the outer radius is used to compute the verts of the bounding box that is
1815 // rendered and the outset ensures the box will cover all partially covered by the rrect
1816 // corners.
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001817 outerRadius += SK_ScalarHalf;
1818 innerRadius -= SK_ScalarHalf;
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001819
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001820 // Expand the rect so all the pixels will be captured.
joshualittd96a67b2015-05-05 14:09:05 -07001821 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001822
joshualitt76e7fb62015-02-11 08:52:27 -08001823 RRectCircleRendererBatch::Geometry geometry;
1824 geometry.fViewMatrix = viewMatrix;
1825 geometry.fColor = color;
1826 geometry.fInnerRadius = innerRadius;
1827 geometry.fOuterRadius = outerRadius;
1828 geometry.fStroke = isStrokeOnly;
joshualittd96a67b2015-05-05 14:09:05 -07001829 geometry.fDevBounds = bounds;
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001830
bsalomoned0bcad2015-05-04 10:36:42 -07001831 return RRectCircleRendererBatch::Create(geometry);
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001832 // otherwise we use the ellipse renderer
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001833 } else {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001834 SkScalar innerXRadius = 0.0f;
1835 SkScalar innerYRadius = 0.0f;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001836 if (hasStroke) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001837 if (SkScalarNearlyZero(scaledStroke.length())) {
1838 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1839 } else {
1840 scaledStroke.scale(SK_ScalarHalf);
1841 }
1842
1843 // we only handle thick strokes for near-circular ellipses
skia.committer@gmail.com8be02fc2013-05-17 07:01:11 +00001844 if (scaledStroke.length() > SK_ScalarHalf &&
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001845 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001846 return nullptr;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001847 }
1848
1849 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1850 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
1851 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
halcanary96fcdcc2015-08-27 07:41:13 -07001852 return nullptr;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001853 }
1854
1855 // this is legit only if scale & translation (which should be the case at the moment)
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001856 if (isStrokeOnly) {
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001857 innerXRadius = xRadius - scaledStroke.fX;
1858 innerYRadius = yRadius - scaledStroke.fY;
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001859 }
1860
1861 xRadius += scaledStroke.fX;
1862 yRadius += scaledStroke.fY;
joshualittd96a67b2015-05-05 14:09:05 -07001863 bounds.outset(scaledStroke.fX, scaledStroke.fY);
commit-bot@chromium.org6bb3efc2013-05-16 13:14:46 +00001864 }
jvanverth@google.come3647412013-05-08 15:31:43 +00001865
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001866 isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
commit-bot@chromium.orgcefde6e2013-08-30 16:34:52 +00001867
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001868 // Expand the rect so all the pixels will be captured.
joshualittd96a67b2015-05-05 14:09:05 -07001869 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001870
joshualitt76e7fb62015-02-11 08:52:27 -08001871 RRectEllipseRendererBatch::Geometry geometry;
1872 geometry.fViewMatrix = viewMatrix;
1873 geometry.fColor = color;
1874 geometry.fXRadius = xRadius;
1875 geometry.fYRadius = yRadius;
1876 geometry.fInnerXRadius = innerXRadius;
1877 geometry.fInnerYRadius = innerYRadius;
1878 geometry.fStroke = isStrokeOnly;
joshualittd96a67b2015-05-05 14:09:05 -07001879 geometry.fDevBounds = bounds;
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001880
bsalomoned0bcad2015-05-04 10:36:42 -07001881 return RRectEllipseRendererBatch::Create(geometry);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001882 }
joshualitt3e708c52015-04-30 13:49:27 -07001883}
1884
robertphillipsb56f9272016-02-25 11:03:52 -08001885GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color,
robertphillips0cc2f852016-02-24 13:36:56 -08001886 const SkMatrix& viewMatrix,
robertphillips0cc2f852016-02-24 13:36:56 -08001887 const SkRRect& rrect,
1888 const SkStrokeRec& stroke,
1889 GrShaderCaps* shaderCaps) {
robertphillips0cc2f852016-02-24 13:36:56 -08001890 if (rrect.isOval()) {
robertphillipsb56f9272016-02-25 11:03:52 -08001891 return CreateOvalBatch(color, viewMatrix, rrect.getBounds(), stroke, shaderCaps);
joshualitt3e708c52015-04-30 13:49:27 -07001892 }
1893
1894 if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
robertphillips0cc2f852016-02-24 13:36:56 -08001895 return nullptr;
joshualitt3e708c52015-04-30 13:49:27 -07001896 }
1897
robertphillips0cc2f852016-02-24 13:36:56 -08001898 return create_rrect_batch(color, viewMatrix, rrect, stroke);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001899}
joshualitt3e708c52015-04-30 13:49:27 -07001900
1901///////////////////////////////////////////////////////////////////////////////////////////////////
1902
1903#ifdef GR_TEST_UTILS
1904
bsalomonabd30f52015-08-13 13:34:48 -07001905DRAW_BATCH_TEST_DEFINE(CircleBatch) {
joshualitt3e708c52015-04-30 13:49:27 -07001906 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1907 GrColor color = GrRandomColor(random);
joshualitt6c891102015-05-13 08:51:49 -07001908 SkRect circle = GrTest::TestSquare(random);
robertphillips0cc2f852016-02-24 13:36:56 -08001909 return create_circle_batch(color, viewMatrix, circle, GrTest::TestStrokeRec(random));
joshualitt3e708c52015-04-30 13:49:27 -07001910}
1911
bsalomonabd30f52015-08-13 13:34:48 -07001912DRAW_BATCH_TEST_DEFINE(EllipseBatch) {
joshualitt3e708c52015-04-30 13:49:27 -07001913 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
1914 GrColor color = GrRandomColor(random);
joshualitt6c891102015-05-13 08:51:49 -07001915 SkRect ellipse = GrTest::TestSquare(random);
robertphillips0cc2f852016-02-24 13:36:56 -08001916 return create_ellipse_batch(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
joshualitt3e708c52015-04-30 13:49:27 -07001917}
1918
bsalomonabd30f52015-08-13 13:34:48 -07001919DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) {
joshualitt3e708c52015-04-30 13:49:27 -07001920 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1921 GrColor color = GrRandomColor(random);
joshualitt6c891102015-05-13 08:51:49 -07001922 SkRect ellipse = GrTest::TestSquare(random);
robertphillips0cc2f852016-02-24 13:36:56 -08001923 return create_diellipse_batch(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
joshualitt3e708c52015-04-30 13:49:27 -07001924}
1925
bsalomonabd30f52015-08-13 13:34:48 -07001926DRAW_BATCH_TEST_DEFINE(RRectBatch) {
joshualitt3e708c52015-04-30 13:49:27 -07001927 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
1928 GrColor color = GrRandomColor(random);
1929 const SkRRect& rrect = GrTest::TestRRectSimple(random);
joshualitt21279c72015-05-11 07:21:37 -07001930 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(random));
joshualitt3e708c52015-04-30 13:49:27 -07001931}
1932
1933#endif