Create GLSLUniformHandler class for gpu backend
[platform/upstream/libSkiaSharp.git] / src / gpu / GrOvalRenderer.cpp
1 /*
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
10 #include "GrBatchFlushState.h"
11 #include "GrBatchTest.h"
12 #include "GrDrawTarget.h"
13 #include "GrGeometryProcessor.h"
14 #include "GrInvariantOutput.h"
15 #include "GrPipelineBuilder.h"
16 #include "GrProcessor.h"
17 #include "GrResourceProvider.h"
18 #include "GrVertexBuffer.h"
19 #include "SkRRect.h"
20 #include "SkStrokeRec.h"
21 #include "SkTLazy.h"
22 #include "batches/GrVertexBatch.h"
23 #include "effects/GrRRectEffect.h"
24 #include "glsl/GrGLSLFragmentShaderBuilder.h"
25 #include "glsl/GrGLSLGeometryProcessor.h"
26 #include "glsl/GrGLSLProgramDataManager.h"
27 #include "glsl/GrGLSLVarying.h"
28 #include "glsl/GrGLSLVertexShaderBuilder.h"
29 #include "glsl/GrGLSLUniformHandler.h"
30 #include "glsl/GrGLSLUtil.h"
31
32 // TODO(joshualitt) - Break this file up during GrBatch post implementation cleanup
33
34 namespace {
35 // TODO(joshualitt) add per vertex colors
36 struct CircleVertex {
37     SkPoint  fPos;
38     SkPoint  fOffset;
39     SkScalar fOuterRadius;
40     SkScalar fInnerRadius;
41 };
42
43 struct EllipseVertex {
44     SkPoint  fPos;
45     SkPoint  fOffset;
46     SkPoint  fOuterRadii;
47     SkPoint  fInnerRadii;
48 };
49
50 struct DIEllipseVertex {
51     SkPoint  fPos;
52     SkPoint  fOuterOffset;
53     SkPoint  fInnerOffset;
54 };
55
56 inline bool circle_stays_circle(const SkMatrix& m) {
57     return m.isSimilarity();
58 }
59
60 }
61
62 ///////////////////////////////////////////////////////////////////////////////
63
64 /**
65  * The output of this effect is a modulation of the input color and coverage for a circle. It
66  * operates in a space normalized by the circle radius (outer radius in the case of a stroke)
67  * with origin at the circle center. Two   vertex attributes are used:
68  *    vec2f : position in device space of the bounding geometry vertices
69  *    vec4f : (p.xy, outerRad, innerRad)
70  *             p is the position in the normalized space.
71  *             outerRad is the outerRadius in device space.
72  *             innerRad is the innerRadius in normalized space (ignored if not stroking).
73  */
74
75 class CircleEdgeEffect : public GrGeometryProcessor {
76 public:
77     static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix,
78                                        bool usesLocalCoords) {
79         return new CircleEdgeEffect(color, stroke, localMatrix, usesLocalCoords);
80     }
81
82     const Attribute* inPosition() const { return fInPosition; }
83     const Attribute* inCircleEdge() const { return fInCircleEdge; }
84     GrColor color() const { return fColor; }
85     bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
86     const SkMatrix& localMatrix() const { return fLocalMatrix; }
87     bool usesLocalCoords() const { return fUsesLocalCoords; }
88     virtual ~CircleEdgeEffect() {}
89
90     const char* name() const override { return "CircleEdge"; }
91
92     inline bool isStroked() const { return fStroke; }
93
94     class GLSLProcessor : public GrGLSLGeometryProcessor {
95     public:
96         GLSLProcessor()
97             : fColor(GrColor_ILLEGAL) {}
98
99         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
100             const CircleEdgeEffect& ce = args.fGP.cast<CircleEdgeEffect>();
101             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
102             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
103             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
104
105             // emit attributes
106             varyingHandler->emitAttributes(ce);
107
108             GrGLSLVertToFrag v(kVec4f_GrSLType);
109             varyingHandler->addVarying("CircleEdge", &v);
110             vertBuilder->codeAppendf("%s = %s;", v.vsOut(), ce.inCircleEdge()->fName);
111
112             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
113             // setup pass through color
114             if (!ce.colorIgnored()) {
115                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
116                                         &fColorUniform);
117             }
118
119             // Setup position
120             this->setupPosition(vertBuilder, gpArgs, ce.inPosition()->fName);
121
122             // emit transforms
123             this->emitTransforms(vertBuilder,
124                                  varyingHandler,
125                                  uniformHandler,
126                                  gpArgs->fPositionVar,
127                                  ce.inPosition()->fName,
128                                  ce.localMatrix(),
129                                  args.fTransformsIn,
130                                  args.fTransformsOut);
131
132             fragBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn());
133             fragBuilder->codeAppendf("float edgeAlpha = clamp(%s.z * (1.0 - d), 0.0, 1.0);",
134                                      v.fsIn());
135             if (ce.isStroked()) {
136                 fragBuilder->codeAppendf("float innerAlpha = clamp(%s.z * (d - %s.w), 0.0, 1.0);",
137                                          v.fsIn(), v.fsIn());
138                 fragBuilder->codeAppend("edgeAlpha *= innerAlpha;");
139             }
140
141             fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
142         }
143
144         static void GenKey(const GrGeometryProcessor& gp,
145                            const GrGLSLCaps&,
146                            GrProcessorKeyBuilder* b) {
147             const CircleEdgeEffect& ce = gp.cast<CircleEdgeEffect>();
148             uint16_t key = ce.isStroked() ? 0x1 : 0x0;
149             key |= ce.usesLocalCoords() && ce.localMatrix().hasPerspective() ? 0x2 : 0x0;
150             key |= ce.colorIgnored() ? 0x4 : 0x0;
151             b->add32(key);
152         }
153
154         void setData(const GrGLSLProgramDataManager& pdman,
155                      const GrPrimitiveProcessor& gp) override {
156             const CircleEdgeEffect& ce = gp.cast<CircleEdgeEffect>();
157             if (ce.color() != fColor) {
158                 float c[4];
159                 GrColorToRGBAFloat(ce.color(), c);
160                 pdman.set4fv(fColorUniform, 1, c);
161                 fColor = ce.color();
162             }
163         }
164
165         void setTransformData(const GrPrimitiveProcessor& primProc,
166                               const GrGLSLProgramDataManager& pdman,
167                               int index,
168                               const SkTArray<const GrCoordTransform*, true>& transforms) override {
169             this->setTransformDataHelper<CircleEdgeEffect>(primProc, pdman, index, transforms);
170         }
171
172     private:
173         GrColor fColor;
174         UniformHandle fColorUniform;
175         typedef GrGLSLGeometryProcessor INHERITED;
176     };
177
178     void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
179         GLSLProcessor::GenKey(*this, caps, b);
180     }
181
182     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
183         return new GLSLProcessor();
184     }
185
186 private:
187     CircleEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix, bool usesLocalCoords)
188         : fColor(color)
189         , fLocalMatrix(localMatrix)
190         , fUsesLocalCoords(usesLocalCoords) {
191         this->initClassID<CircleEdgeEffect>();
192         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
193                                                        kHigh_GrSLPrecision));
194         fInCircleEdge = &this->addVertexAttrib(Attribute("inCircleEdge",
195                                                            kVec4f_GrVertexAttribType));
196         fStroke = stroke;
197     }
198
199     GrColor fColor;
200     SkMatrix fLocalMatrix;
201     const Attribute* fInPosition;
202     const Attribute* fInCircleEdge;
203     bool fStroke;
204     bool fUsesLocalCoords;
205
206     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
207
208     typedef GrGeometryProcessor INHERITED;
209 };
210
211 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleEdgeEffect);
212
213 const GrGeometryProcessor* CircleEdgeEffect::TestCreate(GrProcessorTestData* d) {
214     return CircleEdgeEffect::Create(GrRandomColor(d->fRandom),
215                                     d->fRandom->nextBool(),
216                                     GrTest::TestMatrix(d->fRandom),
217                                     d->fRandom->nextBool());
218 }
219
220 ///////////////////////////////////////////////////////////////////////////////
221
222 /**
223  * The output of this effect is a modulation of the input color and coverage for an axis-aligned
224  * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii,
225  * in both x and y directions.
226  *
227  * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
228  */
229
230 class EllipseEdgeEffect : public GrGeometryProcessor {
231 public:
232     static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix,
233                                        bool usesLocalCoords) {
234         return new EllipseEdgeEffect(color, stroke, localMatrix, usesLocalCoords);
235     }
236
237     virtual ~EllipseEdgeEffect() {}
238
239     const char* name() const override { return "EllipseEdge"; }
240
241     const Attribute* inPosition() const { return fInPosition; }
242     const Attribute* inEllipseOffset() const { return fInEllipseOffset; }
243     const Attribute* inEllipseRadii() const { return fInEllipseRadii; }
244     GrColor color() const { return fColor; }
245     bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
246     const SkMatrix& localMatrix() const { return fLocalMatrix; }
247     bool usesLocalCoords() const { return fUsesLocalCoords; }
248
249     inline bool isStroked() const { return fStroke; }
250
251     class GLSLProcessor : public GrGLSLGeometryProcessor {
252     public:
253         GLSLProcessor()
254             : fColor(GrColor_ILLEGAL) {}
255
256         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
257             const EllipseEdgeEffect& ee = args.fGP.cast<EllipseEdgeEffect>();
258             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
259             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
260             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
261
262             // emit attributes
263             varyingHandler->emitAttributes(ee);
264
265             GrGLSLVertToFrag ellipseOffsets(kVec2f_GrSLType);
266             varyingHandler->addVarying("EllipseOffsets", &ellipseOffsets);
267             vertBuilder->codeAppendf("%s = %s;", ellipseOffsets.vsOut(),
268                                    ee.inEllipseOffset()->fName);
269
270             GrGLSLVertToFrag ellipseRadii(kVec4f_GrSLType);
271             varyingHandler->addVarying("EllipseRadii", &ellipseRadii);
272             vertBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(),
273                                    ee.inEllipseRadii()->fName);
274
275             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
276             // setup pass through color
277             if (!ee.colorIgnored()) {
278                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
279                                         &fColorUniform);
280             }
281
282             // Setup position
283             this->setupPosition(vertBuilder, gpArgs, ee.inPosition()->fName);
284
285             // emit transforms
286             this->emitTransforms(vertBuilder,
287                                  varyingHandler,
288                                  uniformHandler,
289                                  gpArgs->fPositionVar,
290                                  ee.inPosition()->fName,
291                                  ee.localMatrix(),
292                                  args.fTransformsIn,
293                                  args.fTransformsOut);
294
295             // for outer curve
296             fragBuilder->codeAppendf("vec2 scaledOffset = %s*%s.xy;", ellipseOffsets.fsIn(),
297                                      ellipseRadii.fsIn());
298             fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
299             fragBuilder->codeAppendf("vec2 grad = 2.0*scaledOffset*%s.xy;", ellipseRadii.fsIn());
300             fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
301
302             // avoid calling inversesqrt on zero.
303             fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
304             fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
305             fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
306
307             // for inner curve
308             if (ee.isStroked()) {
309                 fragBuilder->codeAppendf("scaledOffset = %s*%s.zw;",
310                                          ellipseOffsets.fsIn(), ellipseRadii.fsIn());
311                 fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
312                 fragBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;",
313                                          ellipseRadii.fsIn());
314                 fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
315                 fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
316             }
317
318             fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
319         }
320
321         static void GenKey(const GrGeometryProcessor& gp,
322                            const GrGLSLCaps&,
323                            GrProcessorKeyBuilder* b) {
324             const EllipseEdgeEffect& ee = gp.cast<EllipseEdgeEffect>();
325             uint16_t key = ee.isStroked() ? 0x1 : 0x0;
326             key |= ee.usesLocalCoords() && ee.localMatrix().hasPerspective() ? 0x2 : 0x0;
327             key |= ee.colorIgnored() ? 0x4 : 0x0;
328             b->add32(key);
329         }
330
331         void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp) override {
332             const EllipseEdgeEffect& ee = gp.cast<EllipseEdgeEffect>();
333             if (ee.color() != fColor) {
334                 float c[4];
335                 GrColorToRGBAFloat(ee.color(), c);
336                 pdman.set4fv(fColorUniform, 1, c);
337                 fColor = ee.color();
338             }
339         }
340
341         void setTransformData(const GrPrimitiveProcessor& primProc,
342                               const GrGLSLProgramDataManager& pdman,
343                               int index,
344                               const SkTArray<const GrCoordTransform*, true>& transforms) override {
345             this->setTransformDataHelper<EllipseEdgeEffect>(primProc, pdman, index, transforms);
346         }
347
348     private:
349         GrColor fColor;
350         UniformHandle fColorUniform;
351
352         typedef GrGLSLGeometryProcessor INHERITED;
353     };
354
355     void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
356         GLSLProcessor::GenKey(*this, caps, b);
357     }
358
359     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
360         return new GLSLProcessor();
361     }
362
363 private:
364     EllipseEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix,
365                       bool usesLocalCoords)
366         : fColor(color)
367         , fLocalMatrix(localMatrix)
368         , fUsesLocalCoords(usesLocalCoords) {
369         this->initClassID<EllipseEdgeEffect>();
370         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
371         fInEllipseOffset = &this->addVertexAttrib(Attribute("inEllipseOffset",
372                                                             kVec2f_GrVertexAttribType));
373         fInEllipseRadii = &this->addVertexAttrib(Attribute("inEllipseRadii",
374                                                            kVec4f_GrVertexAttribType));
375         fStroke = stroke;
376     }
377
378     const Attribute* fInPosition;
379     const Attribute* fInEllipseOffset;
380     const Attribute* fInEllipseRadii;
381     GrColor fColor;
382     SkMatrix fLocalMatrix;
383     bool fStroke;
384     bool fUsesLocalCoords;
385
386     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
387
388     typedef GrGeometryProcessor INHERITED;
389 };
390
391 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseEdgeEffect);
392
393 const GrGeometryProcessor* EllipseEdgeEffect::TestCreate(GrProcessorTestData* d) {
394     return EllipseEdgeEffect::Create(GrRandomColor(d->fRandom),
395                                      d->fRandom->nextBool(),
396                                      GrTest::TestMatrix(d->fRandom),
397                                      d->fRandom->nextBool());
398 }
399
400 ///////////////////////////////////////////////////////////////////////////////
401
402 /**
403  * The output of this effect is a modulation of the input color and coverage for an ellipse,
404  * specified as a 2D offset from center for both the outer and inner paths (if stroked). The
405  * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge corrected by
406  * using differentials.
407  *
408  * The result is device-independent and can be used with any affine matrix.
409  */
410
411 class DIEllipseEdgeEffect : public GrGeometryProcessor {
412 public:
413     enum Mode { kStroke = 0, kHairline, kFill };
414
415     static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, Mode mode,
416                                        bool usesLocalCoords) {
417         return new DIEllipseEdgeEffect(color, viewMatrix, mode, usesLocalCoords);
418     }
419
420     virtual ~DIEllipseEdgeEffect() {}
421
422     const char* name() const override { return "DIEllipseEdge"; }
423
424     const Attribute* inPosition() const { return fInPosition; }
425     const Attribute* inEllipseOffsets0() const { return fInEllipseOffsets0; }
426     const Attribute* inEllipseOffsets1() const { return fInEllipseOffsets1; }
427     GrColor color() const { return fColor; }
428     bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
429     const SkMatrix& viewMatrix() const { return fViewMatrix; }
430     bool usesLocalCoords() const { return fUsesLocalCoords; }
431
432     inline Mode getMode() const { return fMode; }
433
434     class GLSLProcessor : public GrGLSLGeometryProcessor {
435     public:
436         GLSLProcessor()
437             : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL) {}
438
439         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
440             const DIEllipseEdgeEffect& ee = args.fGP.cast<DIEllipseEdgeEffect>();
441             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
442             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
443             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
444
445             // emit attributes
446             varyingHandler->emitAttributes(ee);
447
448             GrGLSLVertToFrag offsets0(kVec2f_GrSLType);
449             varyingHandler->addVarying("EllipseOffsets0", &offsets0);
450             vertBuilder->codeAppendf("%s = %s;", offsets0.vsOut(),
451                                    ee.inEllipseOffsets0()->fName);
452
453             GrGLSLVertToFrag offsets1(kVec2f_GrSLType);
454             varyingHandler->addVarying("EllipseOffsets1", &offsets1);
455             vertBuilder->codeAppendf("%s = %s;", offsets1.vsOut(),
456                                    ee.inEllipseOffsets1()->fName);
457
458             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
459             // setup pass through color
460             if (!ee.colorIgnored()) {
461                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
462                                         &fColorUniform);
463             }
464
465             // Setup position
466             this->setupPosition(vertBuilder,
467                                 uniformHandler,
468                                 gpArgs,
469                                 ee.inPosition()->fName,
470                                 ee.viewMatrix(),
471                                 &fViewMatrixUniform);
472
473             // emit transforms
474             this->emitTransforms(vertBuilder,
475                                  varyingHandler,
476                                  uniformHandler,
477                                  gpArgs->fPositionVar,
478                                  ee.inPosition()->fName,
479                                  args.fTransformsIn,
480                                  args.fTransformsOut);
481
482             SkAssertResult(fragBuilder->enableFeature(
483                     GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
484             // for outer curve
485             fragBuilder->codeAppendf("vec2 scaledOffset = %s.xy;", offsets0.fsIn());
486             fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
487             fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s);", offsets0.fsIn());
488             fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s);", offsets0.fsIn());
489             fragBuilder->codeAppendf("vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
490                                      "                 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
491                                      offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn());
492
493             fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
494             // avoid calling inversesqrt on zero.
495             fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
496             fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
497             if (kHairline == ee.getMode()) {
498                 // can probably do this with one step
499                 fragBuilder->codeAppend("float edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);");
500                 fragBuilder->codeAppend("edgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);");
501             } else {
502                 fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
503             }
504
505             // for inner curve
506             if (kStroke == ee.getMode()) {
507                 fragBuilder->codeAppendf("scaledOffset = %s.xy;", offsets1.fsIn());
508                 fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
509                 fragBuilder->codeAppendf("duvdx = dFdx(%s);", offsets1.fsIn());
510                 fragBuilder->codeAppendf("duvdy = dFdy(%s);", offsets1.fsIn());
511                 fragBuilder->codeAppendf("grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
512                                          "            2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
513                                          offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(),
514                                          offsets1.fsIn());
515                 fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
516                 fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
517             }
518
519             fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
520         }
521
522         static void GenKey(const GrGeometryProcessor& gp,
523                            const GrGLSLCaps&,
524                            GrProcessorKeyBuilder* b) {
525             const DIEllipseEdgeEffect& ellipseEffect = gp.cast<DIEllipseEdgeEffect>();
526             uint16_t key = ellipseEffect.getMode();
527             key |= ellipseEffect.colorIgnored() << 9;
528             key |= ComputePosKey(ellipseEffect.viewMatrix()) << 10;
529             b->add32(key);
530         }
531
532         void setData(const GrGLSLProgramDataManager& pdman,
533                      const GrPrimitiveProcessor& gp) override {
534             const DIEllipseEdgeEffect& dee = gp.cast<DIEllipseEdgeEffect>();
535
536             if (!dee.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dee.viewMatrix())) {
537                 fViewMatrix = dee.viewMatrix();
538                 float viewMatrix[3 * 3];
539                 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
540                 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
541             }
542
543             if (dee.color() != fColor) {
544                 float c[4];
545                 GrColorToRGBAFloat(dee.color(), c);
546                 pdman.set4fv(fColorUniform, 1, c);
547                 fColor = dee.color();
548             }
549         }
550
551     private:
552         SkMatrix fViewMatrix;
553         GrColor fColor;
554         UniformHandle fColorUniform;
555         UniformHandle fViewMatrixUniform;
556
557         typedef GrGLSLGeometryProcessor INHERITED;
558     };
559
560     void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
561         GLSLProcessor::GenKey(*this, caps, b);
562     }
563
564     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
565         return new GLSLProcessor();
566     }
567
568 private:
569     DIEllipseEdgeEffect(GrColor color, const SkMatrix& viewMatrix, Mode mode,
570                         bool usesLocalCoords)
571         : fColor(color)
572         , fViewMatrix(viewMatrix)
573         , fUsesLocalCoords(usesLocalCoords) {
574         this->initClassID<DIEllipseEdgeEffect>();
575         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
576                                                        kHigh_GrSLPrecision));
577         fInEllipseOffsets0 = &this->addVertexAttrib(Attribute("inEllipseOffsets0",
578                                                               kVec2f_GrVertexAttribType));
579         fInEllipseOffsets1 = &this->addVertexAttrib(Attribute("inEllipseOffsets1",
580                                                               kVec2f_GrVertexAttribType));
581         fMode = mode;
582     }
583
584     const Attribute* fInPosition;
585     const Attribute* fInEllipseOffsets0;
586     const Attribute* fInEllipseOffsets1;
587     GrColor fColor;
588     SkMatrix fViewMatrix;
589     Mode fMode;
590     bool fUsesLocalCoords;
591
592     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
593
594     typedef GrGeometryProcessor INHERITED;
595 };
596
597 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseEdgeEffect);
598
599 const GrGeometryProcessor* DIEllipseEdgeEffect::TestCreate(GrProcessorTestData* d) {
600     return DIEllipseEdgeEffect::Create(GrRandomColor(d->fRandom),
601                                        GrTest::TestMatrix(d->fRandom),
602                                        (Mode)(d->fRandom->nextRangeU(0,2)),
603                                        d->fRandom->nextBool());
604 }
605
606 ///////////////////////////////////////////////////////////////////////////////
607
608 bool GrOvalRenderer::DrawOval(GrDrawTarget* target,
609                               const GrPipelineBuilder& pipelineBuilder,
610                               GrColor color,
611                               const SkMatrix& viewMatrix,
612                               bool useAA,
613                               const SkRect& oval,
614                               const SkStrokeRec& stroke) {
615     bool useCoverageAA = useAA && !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
616
617     if (!useCoverageAA) {
618         return false;
619     }
620
621     // we can draw circles
622     if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(viewMatrix)) {
623         DrawCircle(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval, stroke);
624     // if we have shader derivative support, render as device-independent
625     } else if (target->caps()->shaderCaps()->shaderDerivativeSupport()) {
626         return DrawDIEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
627                              stroke);
628     // otherwise axis-aligned ellipses only
629     } else if (viewMatrix.rectStaysRect()) {
630         return DrawEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
631                            stroke);
632     } else {
633         return false;
634     }
635
636     return true;
637 }
638
639 ///////////////////////////////////////////////////////////////////////////////
640
641 class CircleBatch : public GrVertexBatch {
642 public:
643     DEFINE_BATCH_CLASS_ID
644
645     struct Geometry {
646         SkMatrix fViewMatrix;
647         SkRect fDevBounds;
648         SkScalar fInnerRadius;
649         SkScalar fOuterRadius;
650         GrColor fColor;
651         bool fStroke;
652     };
653
654     static GrDrawBatch* Create(const Geometry& geometry) { return new CircleBatch(geometry); }
655
656     const char* name() const override { return "CircleBatch"; }
657
658     SkString dumpInfo() const override {
659         SkString string;
660         for (int i = 0; i < fGeoData.count(); ++i) {
661             string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
662                            "InnerRad: %.2f, OuterRad: %.2f\n",
663                            fGeoData[i].fColor,
664                            fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
665                            fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
666                            fGeoData[i].fInnerRadius,
667                            fGeoData[i].fOuterRadius);
668         }
669         string.append(INHERITED::dumpInfo());
670         return string;
671     }
672
673     void computePipelineOptimizations(GrInitInvariantOutput* color, 
674                                       GrInitInvariantOutput* coverage,
675                                       GrBatchToXPOverrides* overrides) const override {
676         // When this is called on a batch, there is only one geometry bundle
677         color->setKnownFourComponents(fGeoData[0].fColor);
678         coverage->setUnknownSingleComponent();
679         overrides->fUsePLSDstRead = false;
680     }
681
682 private:
683     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
684         // Handle any color overrides
685         if (!overrides.readsColor()) {
686             fGeoData[0].fColor = GrColor_ILLEGAL;
687         }
688         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
689
690         // setup batch properties
691         fBatch.fColorIgnored = !overrides.readsColor();
692         fBatch.fColor = fGeoData[0].fColor;
693         fBatch.fStroke = fGeoData[0].fStroke;
694         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
695         fBatch.fCoverageIgnored = !overrides.readsCoverage();
696     }
697
698     void onPrepareDraws(Target* target) const override {
699         SkMatrix invert;
700         if (!this->viewMatrix().invert(&invert)) {
701             return;
702         }
703
704         // Setup geometry processor
705         SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
706                                                                       this->stroke(),
707                                                                       invert,
708                                                                       this->usesLocalCoords()));
709
710         target->initDraw(gp, this->pipeline());
711
712         int instanceCount = fGeoData.count();
713         size_t vertexStride = gp->getVertexStride();
714         SkASSERT(vertexStride == sizeof(CircleVertex));
715         QuadHelper helper;
716         CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target, vertexStride,
717                                                                           instanceCount));
718         if (!verts) {
719             return;
720         }
721
722         for (int i = 0; i < instanceCount; i++) {
723             const Geometry& geom = fGeoData[i];
724
725             SkScalar innerRadius = geom.fInnerRadius;
726             SkScalar outerRadius = geom.fOuterRadius;
727
728             const SkRect& bounds = geom.fDevBounds;
729
730             // The inner radius in the vertex data must be specified in normalized space.
731             innerRadius = innerRadius / outerRadius;
732             verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
733             verts[0].fOffset = SkPoint::Make(-1, -1);
734             verts[0].fOuterRadius = outerRadius;
735             verts[0].fInnerRadius = innerRadius;
736
737             verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
738             verts[1].fOffset = SkPoint::Make(-1, 1);
739             verts[1].fOuterRadius = outerRadius;
740             verts[1].fInnerRadius = innerRadius;
741
742             verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
743             verts[2].fOffset = SkPoint::Make(1, 1);
744             verts[2].fOuterRadius = outerRadius;
745             verts[2].fInnerRadius = innerRadius;
746
747             verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
748             verts[3].fOffset = SkPoint::Make(1, -1);
749             verts[3].fOuterRadius = outerRadius;
750             verts[3].fInnerRadius = innerRadius;
751
752             verts += kVerticesPerQuad;
753         }
754         helper.recordDraw(target);
755     }
756
757     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
758
759     CircleBatch(const Geometry& geometry) : INHERITED(ClassID()) {
760         fGeoData.push_back(geometry);
761
762         this->setBounds(geometry.fDevBounds);
763     }
764
765     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
766         CircleBatch* that = t->cast<CircleBatch>();
767         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
768                                     that->bounds(), caps)) {
769             return false;
770         }
771
772         // TODO use vertex color to avoid breaking batches
773         if (this->color() != that->color()) {
774             return false;
775         }
776
777         if (this->stroke() != that->stroke()) {
778             return false;
779         }
780
781         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
782         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
783             return false;
784         }
785
786         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
787         this->joinBounds(that->bounds());
788         return true;
789     }
790
791     GrColor color() const { return fBatch.fColor; }
792     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
793     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
794     bool stroke() const { return fBatch.fStroke; }
795
796     struct BatchTracker {
797         GrColor fColor;
798         bool fStroke;
799         bool fUsesLocalCoords;
800         bool fColorIgnored;
801         bool fCoverageIgnored;
802     };
803
804     BatchTracker fBatch;
805     SkSTArray<1, Geometry, true> fGeoData;
806
807     typedef GrVertexBatch INHERITED;
808 };
809
810 static GrDrawBatch* create_circle_batch(GrColor color,
811                                         const SkMatrix& viewMatrix,
812                                         bool useCoverageAA,
813                                         const SkRect& circle,
814                                         const SkStrokeRec& stroke) {
815     SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
816     viewMatrix.mapPoints(&center, 1);
817     SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
818     SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
819
820     SkStrokeRec::Style style = stroke.getStyle();
821     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
822                         SkStrokeRec::kHairline_Style == style;
823     bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
824
825     SkScalar innerRadius = 0.0f;
826     SkScalar outerRadius = radius;
827     SkScalar halfWidth = 0;
828     if (hasStroke) {
829         if (SkScalarNearlyZero(strokeWidth)) {
830             halfWidth = SK_ScalarHalf;
831         } else {
832             halfWidth = SkScalarHalf(strokeWidth);
833         }
834
835         outerRadius += halfWidth;
836         if (isStrokeOnly) {
837             innerRadius = radius - halfWidth;
838         }
839     }
840
841     // The radii are outset for two reasons. First, it allows the shader to simply perform simpler
842     // computation because the computed alpha is zero, rather than 50%, at the radius.
843     // Second, the outer radius is used to compute the verts of the bounding box that is rendered
844     // and the outset ensures the box will cover all partially covered by the circle.
845     outerRadius += SK_ScalarHalf;
846     innerRadius -= SK_ScalarHalf;
847
848     CircleBatch::Geometry geometry;
849     geometry.fViewMatrix = viewMatrix;
850     geometry.fColor = color;
851     geometry.fInnerRadius = innerRadius;
852     geometry.fOuterRadius = outerRadius;
853     geometry.fStroke = isStrokeOnly && innerRadius > 0;
854     geometry.fDevBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
855                                            center.fX + outerRadius, center.fY + outerRadius);
856
857     return CircleBatch::Create(geometry);
858 }
859
860 void GrOvalRenderer::DrawCircle(GrDrawTarget* target,
861                                 const GrPipelineBuilder& pipelineBuilder,
862                                 GrColor color,
863                                 const SkMatrix& viewMatrix,
864                                 bool useCoverageAA,
865                                 const SkRect& circle,
866                                 const SkStrokeRec& stroke) {
867     SkAutoTUnref<GrDrawBatch> batch(create_circle_batch(color, viewMatrix, useCoverageAA, circle,
868                                                         stroke));
869     target->drawBatch(pipelineBuilder, batch);
870 }
871
872 ///////////////////////////////////////////////////////////////////////////////
873
874 class EllipseBatch : public GrVertexBatch {
875 public:
876     DEFINE_BATCH_CLASS_ID
877
878     struct Geometry {
879         SkMatrix fViewMatrix;
880         SkRect fDevBounds;
881         SkScalar fXRadius;
882         SkScalar fYRadius;
883         SkScalar fInnerXRadius;
884         SkScalar fInnerYRadius;
885         GrColor fColor;
886         bool fStroke;
887     };
888
889     static GrDrawBatch* Create(const Geometry& geometry) { return new EllipseBatch(geometry); }
890
891     const char* name() const override { return "EllipseBatch"; }
892
893     void computePipelineOptimizations(GrInitInvariantOutput* color, 
894                                       GrInitInvariantOutput* coverage,
895                                       GrBatchToXPOverrides* overrides) const override {
896         // When this is called on a batch, there is only one geometry bundle
897         color->setKnownFourComponents(fGeoData[0].fColor);
898         coverage->setUnknownSingleComponent();
899         overrides->fUsePLSDstRead = false;
900     }
901
902 private:
903     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
904         // Handle any color overrides
905         if (!overrides.readsCoverage()) {
906             fGeoData[0].fColor = GrColor_ILLEGAL;
907         }
908         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
909
910         // setup batch properties
911         fBatch.fColorIgnored = !overrides.readsColor();
912         fBatch.fColor = fGeoData[0].fColor;
913         fBatch.fStroke = fGeoData[0].fStroke;
914         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
915         fBatch.fCoverageIgnored = !overrides.readsCoverage();
916     }
917
918     void onPrepareDraws(Target* target) const override {
919         SkMatrix invert;
920         if (!this->viewMatrix().invert(&invert)) {
921             return;
922         }
923
924         // Setup geometry processor
925         SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
926                                                                        this->stroke(),
927                                                                        invert,
928                                                                        this->usesLocalCoords()));
929
930         target->initDraw(gp, this->pipeline());
931
932         int instanceCount = fGeoData.count();
933         QuadHelper helper;
934         size_t vertexStride = gp->getVertexStride();
935         SkASSERT(vertexStride == sizeof(EllipseVertex));
936         EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
937             helper.init(target, vertexStride, instanceCount));
938         if (!verts) {
939             return;
940         }
941
942         for (int i = 0; i < instanceCount; i++) {
943             const Geometry& geom = fGeoData[i];
944
945             SkScalar xRadius = geom.fXRadius;
946             SkScalar yRadius = geom.fYRadius;
947
948             // Compute the reciprocals of the radii here to save time in the shader
949             SkScalar xRadRecip = SkScalarInvert(xRadius);
950             SkScalar yRadRecip = SkScalarInvert(yRadius);
951             SkScalar xInnerRadRecip = SkScalarInvert(geom.fInnerXRadius);
952             SkScalar yInnerRadRecip = SkScalarInvert(geom.fInnerYRadius);
953
954             const SkRect& bounds = geom.fDevBounds;
955
956             // The inner radius in the vertex data must be specified in normalized space.
957             verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
958             verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
959             verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
960             verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
961
962             verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
963             verts[1].fOffset = SkPoint::Make(-xRadius, yRadius);
964             verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
965             verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
966
967             verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
968             verts[2].fOffset = SkPoint::Make(xRadius, yRadius);
969             verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
970             verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
971
972             verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
973             verts[3].fOffset = SkPoint::Make(xRadius, -yRadius);
974             verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
975             verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
976
977             verts += kVerticesPerQuad;
978         }
979         helper.recordDraw(target);
980     }
981
982     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
983
984     EllipseBatch(const Geometry& geometry) : INHERITED(ClassID()) {
985         fGeoData.push_back(geometry);
986
987         this->setBounds(geometry.fDevBounds);
988     }
989
990     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
991         EllipseBatch* that = t->cast<EllipseBatch>();
992
993         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
994                                     that->bounds(), caps)) {
995             return false;
996         }
997
998         // TODO use vertex color to avoid breaking batches
999         if (this->color() != that->color()) {
1000             return false;
1001         }
1002
1003         if (this->stroke() != that->stroke()) {
1004             return false;
1005         }
1006
1007         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1008         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1009             return false;
1010         }
1011
1012         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1013         this->joinBounds(that->bounds());
1014         return true;
1015     }
1016
1017     GrColor color() const { return fBatch.fColor; }
1018     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1019     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1020     bool stroke() const { return fBatch.fStroke; }
1021
1022     struct BatchTracker {
1023         GrColor fColor;
1024         bool fStroke;
1025         bool fUsesLocalCoords;
1026         bool fColorIgnored;
1027         bool fCoverageIgnored;
1028     };
1029
1030     BatchTracker fBatch;
1031     SkSTArray<1, Geometry, true> fGeoData;
1032
1033     typedef GrVertexBatch INHERITED;
1034 };
1035
1036 static GrDrawBatch* create_ellipse_batch(GrColor color,
1037                                          const SkMatrix& viewMatrix,
1038                                          bool useCoverageAA,
1039                                          const SkRect& ellipse,
1040                                          const SkStrokeRec& stroke) {
1041 #ifdef SK_DEBUG
1042     {
1043         // we should have checked for this previously
1044         bool isAxisAlignedEllipse = viewMatrix.rectStaysRect();
1045         SkASSERT(useCoverageAA && isAxisAlignedEllipse);
1046     }
1047 #endif
1048
1049     // do any matrix crunching before we reset the draw state for device coords
1050     SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
1051     viewMatrix.mapPoints(&center, 1);
1052     SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
1053     SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
1054     SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius +
1055                                    viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius);
1056     SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius +
1057                                    viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius);
1058
1059     // do (potentially) anisotropic mapping of stroke
1060     SkVector scaledStroke;
1061     SkScalar strokeWidth = stroke.getWidth();
1062     scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
1063                                                viewMatrix[SkMatrix::kMSkewY]));
1064     scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
1065                                                viewMatrix[SkMatrix::kMScaleY]));
1066
1067     SkStrokeRec::Style style = stroke.getStyle();
1068     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1069                         SkStrokeRec::kHairline_Style == style;
1070     bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
1071
1072     SkScalar innerXRadius = 0;
1073     SkScalar innerYRadius = 0;
1074     if (hasStroke) {
1075         if (SkScalarNearlyZero(scaledStroke.length())) {
1076             scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1077         } else {
1078             scaledStroke.scale(SK_ScalarHalf);
1079         }
1080
1081         // we only handle thick strokes for near-circular ellipses
1082         if (scaledStroke.length() > SK_ScalarHalf &&
1083             (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
1084             return nullptr;
1085         }
1086
1087         // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1088         if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
1089             scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
1090             return nullptr;
1091         }
1092
1093         // this is legit only if scale & translation (which should be the case at the moment)
1094         if (isStrokeOnly) {
1095             innerXRadius = xRadius - scaledStroke.fX;
1096             innerYRadius = yRadius - scaledStroke.fY;
1097         }
1098
1099         xRadius += scaledStroke.fX;
1100         yRadius += scaledStroke.fY;
1101     }
1102
1103     // We've extended the outer x radius out half a pixel to antialias.
1104     // This will also expand the rect so all the pixels will be captured.
1105     // TODO: Consider if we should use sqrt(2)/2 instead
1106     xRadius += SK_ScalarHalf;
1107     yRadius += SK_ScalarHalf;
1108
1109     EllipseBatch::Geometry geometry;
1110     geometry.fViewMatrix = viewMatrix;
1111     geometry.fColor = color;
1112     geometry.fXRadius = xRadius;
1113     geometry.fYRadius = yRadius;
1114     geometry.fInnerXRadius = innerXRadius;
1115     geometry.fInnerYRadius = innerYRadius;
1116     geometry.fStroke = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
1117     geometry.fDevBounds = SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius,
1118                                            center.fX + xRadius, center.fY + yRadius);
1119
1120     return EllipseBatch::Create(geometry);
1121 }
1122
1123 bool GrOvalRenderer::DrawEllipse(GrDrawTarget* target,
1124                                  const GrPipelineBuilder& pipelineBuilder,
1125                                  GrColor color,
1126                                  const SkMatrix& viewMatrix,
1127                                  bool useCoverageAA,
1128                                  const SkRect& ellipse,
1129                                  const SkStrokeRec& stroke) {
1130     SkAutoTUnref<GrDrawBatch> batch(create_ellipse_batch(color, viewMatrix, useCoverageAA, ellipse,
1131                                                          stroke));
1132     if (!batch) {
1133         return false;
1134     }
1135
1136     target->drawBatch(pipelineBuilder, batch);
1137     return true;
1138 }
1139
1140 /////////////////////////////////////////////////////////////////////////////////////////////////
1141
1142 class DIEllipseBatch : public GrVertexBatch {
1143 public:
1144     DEFINE_BATCH_CLASS_ID
1145
1146     struct Geometry {
1147         SkMatrix fViewMatrix;
1148         SkRect fBounds;
1149         SkScalar fXRadius;
1150         SkScalar fYRadius;
1151         SkScalar fInnerXRadius;
1152         SkScalar fInnerYRadius;
1153         SkScalar fGeoDx;
1154         SkScalar fGeoDy;
1155         GrColor fColor;
1156         DIEllipseEdgeEffect::Mode fMode;
1157     };
1158
1159     static GrDrawBatch* Create(const Geometry& geometry, const SkRect& bounds) {
1160         return new DIEllipseBatch(geometry, bounds);
1161     }
1162
1163     const char* name() const override { return "DIEllipseBatch"; }
1164
1165     void computePipelineOptimizations(GrInitInvariantOutput* color, 
1166                                       GrInitInvariantOutput* coverage,
1167                                       GrBatchToXPOverrides* overrides) const override {
1168         // When this is called on a batch, there is only one geometry bundle
1169         color->setKnownFourComponents(fGeoData[0].fColor);
1170         coverage->setUnknownSingleComponent();
1171         overrides->fUsePLSDstRead = false;
1172     }
1173
1174 private:
1175
1176     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1177         // Handle any color overrides
1178         if (!overrides.readsColor()) {
1179             fGeoData[0].fColor = GrColor_ILLEGAL;
1180         }
1181         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1182
1183         // setup batch properties
1184         fBatch.fColorIgnored = !overrides.readsColor();
1185         fBatch.fColor = fGeoData[0].fColor;
1186         fBatch.fMode = fGeoData[0].fMode;
1187         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
1188         fBatch.fCoverageIgnored = !overrides.readsCoverage();
1189     }
1190
1191     void onPrepareDraws(Target* target) const override {
1192         // Setup geometry processor
1193         SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(this->color(),
1194                                                                          this->viewMatrix(),
1195                                                                          this->mode(),
1196                                                                          this->usesLocalCoords()));
1197
1198         target->initDraw(gp, this->pipeline());
1199
1200         int instanceCount = fGeoData.count();
1201         size_t vertexStride = gp->getVertexStride();
1202         SkASSERT(vertexStride == sizeof(DIEllipseVertex));
1203         QuadHelper helper;
1204         DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(
1205             helper.init(target, vertexStride, instanceCount));
1206         if (!verts) {
1207             return;
1208         }
1209
1210         for (int i = 0; i < instanceCount; i++) {
1211             const Geometry& geom = fGeoData[i];
1212
1213             SkScalar xRadius = geom.fXRadius;
1214             SkScalar yRadius = geom.fYRadius;
1215
1216             const SkRect& bounds = geom.fBounds;
1217
1218             // This adjusts the "radius" to include the half-pixel border
1219             SkScalar offsetDx = geom.fGeoDx / xRadius;
1220             SkScalar offsetDy = geom.fGeoDy / yRadius;
1221
1222             SkScalar innerRatioX = xRadius / geom.fInnerXRadius;
1223             SkScalar innerRatioY = yRadius / geom.fInnerYRadius;
1224
1225             verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
1226             verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
1227             verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
1228
1229             verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
1230             verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
1231             verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
1232
1233             verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
1234             verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
1235             verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
1236
1237             verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1238             verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
1239             verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
1240
1241             verts += kVerticesPerQuad;
1242         }
1243         helper.recordDraw(target);
1244     }
1245
1246     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1247
1248     DIEllipseBatch(const Geometry& geometry, const SkRect& bounds) : INHERITED(ClassID()) {
1249         fGeoData.push_back(geometry);
1250
1251         this->setBounds(bounds);
1252     }
1253
1254     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
1255         DIEllipseBatch* that = t->cast<DIEllipseBatch>();
1256         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1257                                     that->bounds(), caps)) {
1258             return false;
1259         }
1260
1261         // TODO use vertex color to avoid breaking batches
1262         if (this->color() != that->color()) {
1263             return false;
1264         }
1265
1266         if (this->mode() != that->mode()) {
1267             return false;
1268         }
1269
1270         // TODO rewrite to allow positioning on CPU
1271         if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1272             return false;
1273         }
1274
1275         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1276         this->joinBounds(that->bounds());
1277         return true;
1278     }
1279
1280     GrColor color() const { return fBatch.fColor; }
1281     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1282     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1283     DIEllipseEdgeEffect::Mode mode() const { return fBatch.fMode; }
1284
1285     struct BatchTracker {
1286         GrColor fColor;
1287         DIEllipseEdgeEffect::Mode fMode;
1288         bool fUsesLocalCoords;
1289         bool fColorIgnored;
1290         bool fCoverageIgnored;
1291     };
1292
1293     BatchTracker fBatch;
1294     SkSTArray<1, Geometry, true> fGeoData;
1295
1296     typedef GrVertexBatch INHERITED;
1297 };
1298
1299 static GrDrawBatch* create_diellipse_batch(GrColor color,
1300                                            const SkMatrix& viewMatrix,
1301                                            bool useCoverageAA,
1302                                            const SkRect& ellipse,
1303                                            const SkStrokeRec& stroke) {
1304     SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
1305     SkScalar xRadius = SkScalarHalf(ellipse.width());
1306     SkScalar yRadius = SkScalarHalf(ellipse.height());
1307
1308     SkStrokeRec::Style style = stroke.getStyle();
1309     DIEllipseEdgeEffect::Mode mode = (SkStrokeRec::kStroke_Style == style) ?
1310                                     DIEllipseEdgeEffect::kStroke :
1311                                     (SkStrokeRec::kHairline_Style == style) ?
1312                                     DIEllipseEdgeEffect::kHairline : DIEllipseEdgeEffect::kFill;
1313
1314     SkScalar innerXRadius = 0;
1315     SkScalar innerYRadius = 0;
1316     if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
1317         SkScalar strokeWidth = stroke.getWidth();
1318
1319         if (SkScalarNearlyZero(strokeWidth)) {
1320             strokeWidth = SK_ScalarHalf;
1321         } else {
1322             strokeWidth *= SK_ScalarHalf;
1323         }
1324
1325         // we only handle thick strokes for near-circular ellipses
1326         if (strokeWidth > SK_ScalarHalf &&
1327             (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
1328             return nullptr;
1329         }
1330
1331         // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1332         if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
1333             strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
1334             return nullptr;
1335         }
1336
1337         // set inner radius (if needed)
1338         if (SkStrokeRec::kStroke_Style == style) {
1339             innerXRadius = xRadius - strokeWidth;
1340             innerYRadius = yRadius - strokeWidth;
1341         }
1342
1343         xRadius += strokeWidth;
1344         yRadius += strokeWidth;
1345     }
1346     if (DIEllipseEdgeEffect::kStroke == mode) {
1347         mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kStroke :
1348                                                         DIEllipseEdgeEffect::kFill;
1349     }
1350
1351     // This expands the outer rect so that after CTM we end up with a half-pixel border
1352     SkScalar a = viewMatrix[SkMatrix::kMScaleX];
1353     SkScalar b = viewMatrix[SkMatrix::kMSkewX];
1354     SkScalar c = viewMatrix[SkMatrix::kMSkewY];
1355     SkScalar d = viewMatrix[SkMatrix::kMScaleY];
1356     SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
1357     SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
1358
1359     DIEllipseBatch::Geometry geometry;
1360     geometry.fViewMatrix = viewMatrix;
1361     geometry.fColor = color;
1362     geometry.fXRadius = xRadius;
1363     geometry.fYRadius = yRadius;
1364     geometry.fInnerXRadius = innerXRadius;
1365     geometry.fInnerYRadius = innerYRadius;
1366     geometry.fGeoDx = geoDx;
1367     geometry.fGeoDy = geoDy;
1368     geometry.fMode = mode;
1369     geometry.fBounds = SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
1370                                         center.fX + xRadius + geoDx, center.fY + yRadius + geoDy);
1371
1372     SkRect devBounds = geometry.fBounds;
1373     viewMatrix.mapRect(&devBounds);
1374     return DIEllipseBatch::Create(geometry, devBounds);
1375 }
1376
1377 bool GrOvalRenderer::DrawDIEllipse(GrDrawTarget* target,
1378                                    const GrPipelineBuilder& pipelineBuilder,
1379                                    GrColor color,
1380                                    const SkMatrix& viewMatrix,
1381                                    bool useCoverageAA,
1382                                    const SkRect& ellipse,
1383                                    const SkStrokeRec& stroke) {
1384     SkAutoTUnref<GrDrawBatch> batch(create_diellipse_batch(color, viewMatrix, useCoverageAA,
1385                                                            ellipse, stroke));
1386     if (!batch) {
1387         return false;
1388     }
1389     target->drawBatch(pipelineBuilder, batch);
1390     return true;
1391 }
1392
1393 ///////////////////////////////////////////////////////////////////////////////
1394
1395 static const uint16_t gRRectIndices[] = {
1396     // corners
1397     0, 1, 5, 0, 5, 4,
1398     2, 3, 7, 2, 7, 6,
1399     8, 9, 13, 8, 13, 12,
1400     10, 11, 15, 10, 15, 14,
1401
1402     // edges
1403     1, 2, 6, 1, 6, 5,
1404     4, 5, 9, 4, 9, 8,
1405     6, 7, 11, 6, 11, 10,
1406     9, 10, 14, 9, 14, 13,
1407
1408     // center
1409     // we place this at the end so that we can ignore these indices when rendering stroke-only
1410     5, 6, 10, 5, 10, 9
1411 };
1412
1413 static const int kIndicesPerStrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
1414 static const int kIndicesPerRRect = SK_ARRAY_COUNT(gRRectIndices);
1415 static const int kVertsPerRRect = 16;
1416 static const int kNumRRectsInIndexBuffer = 256;
1417
1418 GR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1419 GR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1420 static const GrIndexBuffer* ref_rrect_index_buffer(bool strokeOnly,
1421                                                    GrResourceProvider* resourceProvider) {
1422     GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1423     GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1424     if (strokeOnly) {
1425         return resourceProvider->findOrCreateInstancedIndexBuffer(
1426             gRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1427             gStrokeRRectOnlyIndexBufferKey);
1428     } else {
1429         return resourceProvider->findOrCreateInstancedIndexBuffer(
1430             gRRectIndices, kIndicesPerRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
1431             gRRectOnlyIndexBufferKey);
1432
1433     }
1434 }
1435
1436 bool GrOvalRenderer::DrawDRRect(GrDrawTarget* target,
1437                                 const GrPipelineBuilder& pipelineBuilder,
1438                                 GrColor color,
1439                                 const SkMatrix& viewMatrix,
1440                                 bool useAA,
1441                                 const SkRRect& origOuter,
1442                                 const SkRRect& origInner) {
1443     bool applyAA = useAA && !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
1444     GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
1445     if (!origInner.isEmpty()) {
1446         SkTCopyOnFirstWrite<SkRRect> inner(origInner);
1447         if (!viewMatrix.isIdentity()) {
1448             if (!origInner.transform(viewMatrix, inner.writable())) {
1449                 return false;
1450             }
1451         }
1452         GrPrimitiveEdgeType edgeType = applyAA ?
1453                 kInverseFillAA_GrProcessorEdgeType :
1454                 kInverseFillBW_GrProcessorEdgeType;
1455         // TODO this needs to be a geometry processor
1456         GrFragmentProcessor* fp = GrRRectEffect::Create(edgeType, *inner);
1457         if (nullptr == fp) {
1458             return false;
1459         }
1460         arfps.set(&pipelineBuilder);
1461         arfps.addCoverageFragmentProcessor(fp)->unref();
1462     }
1463
1464     SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle);
1465     if (DrawRRect(target, pipelineBuilder, color, viewMatrix, useAA, origOuter, fillRec)) {
1466         return true;
1467     }
1468
1469     SkASSERT(!origOuter.isEmpty());
1470     SkTCopyOnFirstWrite<SkRRect> outer(origOuter);
1471     if (!viewMatrix.isIdentity()) {
1472         if (!origOuter.transform(viewMatrix, outer.writable())) {
1473             return false;
1474         }
1475     }
1476     GrPrimitiveEdgeType edgeType = applyAA ? kFillAA_GrProcessorEdgeType :
1477                                              kFillBW_GrProcessorEdgeType;
1478     GrFragmentProcessor* effect = GrRRectEffect::Create(edgeType, *outer);
1479     if (nullptr == effect) {
1480         return false;
1481     }
1482     if (!arfps.isSet()) {
1483         arfps.set(&pipelineBuilder);
1484     }
1485
1486     SkMatrix invert;
1487     if (!viewMatrix.invert(&invert)) {
1488         return false;
1489     }
1490
1491     arfps.addCoverageFragmentProcessor(effect)->unref();
1492     SkRect bounds = outer->getBounds();
1493     if (applyAA) {
1494         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1495     }
1496     target->drawNonAARect(pipelineBuilder, color, SkMatrix::I(), bounds, invert);
1497     return true;
1498 }
1499
1500 ///////////////////////////////////////////////////////////////////////////////////////////////////
1501
1502 class RRectCircleRendererBatch : public GrVertexBatch {
1503 public:
1504     DEFINE_BATCH_CLASS_ID
1505
1506     struct Geometry {
1507         SkMatrix fViewMatrix;
1508         SkRect fDevBounds;
1509         SkScalar fInnerRadius;
1510         SkScalar fOuterRadius;
1511         GrColor fColor;
1512         bool fStroke;
1513     };
1514
1515     static GrDrawBatch* Create(const Geometry& geometry) {
1516         return new RRectCircleRendererBatch(geometry);
1517     }
1518
1519     const char* name() const override { return "RRectCircleBatch"; }
1520
1521     void computePipelineOptimizations(GrInitInvariantOutput* color, 
1522                                       GrInitInvariantOutput* coverage,
1523                                       GrBatchToXPOverrides* overrides) const override {
1524         // When this is called on a batch, there is only one geometry bundle
1525         color->setKnownFourComponents(fGeoData[0].fColor);
1526         coverage->setUnknownSingleComponent();
1527         overrides->fUsePLSDstRead = false;
1528     }
1529
1530 private:
1531     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1532         // Handle any color overrides
1533         if (!overrides.readsColor()) {
1534             fGeoData[0].fColor = GrColor_ILLEGAL;
1535         }
1536         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1537
1538         // setup batch properties
1539         fBatch.fColorIgnored = !overrides.readsColor();
1540         fBatch.fColor = fGeoData[0].fColor;
1541         fBatch.fStroke = fGeoData[0].fStroke;
1542         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
1543         fBatch.fCoverageIgnored = !overrides.readsCoverage();
1544     }
1545
1546     void onPrepareDraws(Target* target) const override {
1547         // reset to device coordinates
1548         SkMatrix invert;
1549         if (!this->viewMatrix().invert(&invert)) {
1550             SkDebugf("Failed to invert\n");
1551             return;
1552         }
1553
1554         // Setup geometry processor
1555         SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
1556                                                                       this->stroke(),
1557                                                                       invert,
1558                                                                       this->usesLocalCoords()));
1559
1560         target->initDraw(gp, this->pipeline());
1561
1562         int instanceCount = fGeoData.count();
1563         size_t vertexStride = gp->getVertexStride();
1564         SkASSERT(vertexStride == sizeof(CircleVertex));
1565
1566         // drop out the middle quad if we're stroked
1567         int indicesPerInstance = this->stroke() ? kIndicesPerStrokeRRect : kIndicesPerRRect;
1568         SkAutoTUnref<const GrIndexBuffer> indexBuffer(
1569             ref_rrect_index_buffer(this->stroke(), target->resourceProvider()));
1570
1571         InstancedHelper helper;
1572         CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target,
1573             kTriangles_GrPrimitiveType, vertexStride, indexBuffer, kVertsPerRRect,
1574             indicesPerInstance, instanceCount));
1575         if (!verts || !indexBuffer) {
1576             SkDebugf("Could not allocate vertices\n");
1577             return;
1578         }
1579
1580         for (int i = 0; i < instanceCount; i++) {
1581             const Geometry& args = fGeoData[i];
1582
1583             SkScalar outerRadius = args.fOuterRadius;
1584
1585             const SkRect& bounds = args.fDevBounds;
1586
1587             SkScalar yCoords[4] = {
1588                 bounds.fTop,
1589                 bounds.fTop + outerRadius,
1590                 bounds.fBottom - outerRadius,
1591                 bounds.fBottom
1592             };
1593
1594             SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
1595             // The inner radius in the vertex data must be specified in normalized space.
1596             SkScalar innerRadius = args.fInnerRadius / args.fOuterRadius;
1597             for (int i = 0; i < 4; ++i) {
1598                 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1599                 verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
1600                 verts->fOuterRadius = outerRadius;
1601                 verts->fInnerRadius = innerRadius;
1602                 verts++;
1603
1604                 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
1605                 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1606                 verts->fOuterRadius = outerRadius;
1607                 verts->fInnerRadius = innerRadius;
1608                 verts++;
1609
1610                 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
1611                 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1612                 verts->fOuterRadius = outerRadius;
1613                 verts->fInnerRadius = innerRadius;
1614                 verts++;
1615
1616                 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1617                 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
1618                 verts->fOuterRadius = outerRadius;
1619                 verts->fInnerRadius = innerRadius;
1620                 verts++;
1621             }
1622         }
1623
1624         helper.recordDraw(target);
1625     }
1626
1627     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1628
1629     RRectCircleRendererBatch(const Geometry& geometry) : INHERITED(ClassID()) {
1630         fGeoData.push_back(geometry);
1631
1632         this->setBounds(geometry.fDevBounds);
1633     }
1634
1635     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
1636         RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>();
1637         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1638                                     that->bounds(), caps)) {
1639             return false;
1640         }
1641
1642         // TODO use vertex color to avoid breaking batches
1643         if (this->color() != that->color()) {
1644             return false;
1645         }
1646
1647         if (this->stroke() != that->stroke()) {
1648             return false;
1649         }
1650
1651         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1652         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1653             return false;
1654         }
1655
1656         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1657         this->joinBounds(that->bounds());
1658         return true;
1659     }
1660
1661     GrColor color() const { return fBatch.fColor; }
1662     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1663     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1664     bool stroke() const { return fBatch.fStroke; }
1665
1666     struct BatchTracker {
1667         GrColor fColor;
1668         bool fStroke;
1669         bool fUsesLocalCoords;
1670         bool fColorIgnored;
1671         bool fCoverageIgnored;
1672     };
1673
1674     BatchTracker fBatch;
1675     SkSTArray<1, Geometry, true> fGeoData;
1676
1677     typedef GrVertexBatch INHERITED;
1678 };
1679
1680 class RRectEllipseRendererBatch : public GrVertexBatch {
1681 public:
1682     DEFINE_BATCH_CLASS_ID
1683
1684     struct Geometry {
1685         SkMatrix fViewMatrix;
1686         SkRect fDevBounds;
1687         SkScalar fXRadius;
1688         SkScalar fYRadius;
1689         SkScalar fInnerXRadius;
1690         SkScalar fInnerYRadius;
1691         GrColor fColor;
1692         bool fStroke;
1693     };
1694
1695     static GrDrawBatch* Create(const Geometry& geometry) {
1696         return new RRectEllipseRendererBatch(geometry);
1697     }
1698
1699     const char* name() const override { return "RRectEllipseRendererBatch"; }
1700
1701     void computePipelineOptimizations(GrInitInvariantOutput* color, 
1702                                       GrInitInvariantOutput* coverage,
1703                                       GrBatchToXPOverrides* overrides) const override {
1704         // When this is called on a batch, there is only one geometry bundle
1705         color->setKnownFourComponents(fGeoData[0].fColor);
1706         coverage->setUnknownSingleComponent();
1707         overrides->fUsePLSDstRead = false;
1708     }
1709
1710 private:
1711     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1712         // Handle any color overrides
1713         if (!overrides.readsColor()) {
1714             fGeoData[0].fColor = GrColor_ILLEGAL;
1715         }
1716         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1717
1718         // setup batch properties
1719         fBatch.fColorIgnored = !overrides.readsColor();
1720         fBatch.fColor = fGeoData[0].fColor;
1721         fBatch.fStroke = fGeoData[0].fStroke;
1722         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
1723         fBatch.fCoverageIgnored = !overrides.readsCoverage();
1724     }
1725
1726     void onPrepareDraws(Target* target) const override {
1727         // reset to device coordinates
1728         SkMatrix invert;
1729         if (!this->viewMatrix().invert(&invert)) {
1730             SkDebugf("Failed to invert\n");
1731             return;
1732         }
1733
1734         // Setup geometry processor
1735         SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
1736                                                                        this->stroke(),
1737                                                                        invert,
1738                                                                        this->usesLocalCoords()));
1739
1740         target->initDraw(gp, this->pipeline());
1741
1742         int instanceCount = fGeoData.count();
1743         size_t vertexStride = gp->getVertexStride();
1744         SkASSERT(vertexStride == sizeof(EllipseVertex));
1745
1746         // drop out the middle quad if we're stroked
1747         int indicesPerInstance = this->stroke() ? kIndicesPerStrokeRRect : kIndicesPerRRect;
1748         SkAutoTUnref<const GrIndexBuffer> indexBuffer(
1749             ref_rrect_index_buffer(this->stroke(), target->resourceProvider()));
1750
1751         InstancedHelper helper;
1752         EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
1753             helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer,
1754             kVertsPerRRect, indicesPerInstance, instanceCount));
1755         if (!verts || !indexBuffer) {
1756             SkDebugf("Could not allocate vertices\n");
1757             return;
1758         }
1759
1760         for (int i = 0; i < instanceCount; i++) {
1761             const Geometry& args = fGeoData[i];
1762
1763             // Compute the reciprocals of the radii here to save time in the shader
1764             SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
1765             SkScalar yRadRecip = SkScalarInvert(args.fYRadius);
1766             SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
1767             SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
1768
1769             // Extend the radii out half a pixel to antialias.
1770             SkScalar xOuterRadius = args.fXRadius + SK_ScalarHalf;
1771             SkScalar yOuterRadius = args.fYRadius + SK_ScalarHalf;
1772
1773             const SkRect& bounds = args.fDevBounds;
1774
1775             SkScalar yCoords[4] = {
1776                 bounds.fTop,
1777                 bounds.fTop + yOuterRadius,
1778                 bounds.fBottom - yOuterRadius,
1779                 bounds.fBottom
1780             };
1781             SkScalar yOuterOffsets[4] = {
1782                 yOuterRadius,
1783                 SK_ScalarNearlyZero, // we're using inversesqrt() in shader, so can't be exactly 0
1784                 SK_ScalarNearlyZero,
1785                 yOuterRadius
1786             };
1787
1788             for (int i = 0; i < 4; ++i) {
1789                 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1790                 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1791                 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1792                 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1793                 verts++;
1794
1795                 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
1796                 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
1797                 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1798                 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1799                 verts++;
1800
1801                 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
1802                 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
1803                 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1804                 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1805                 verts++;
1806
1807                 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1808                 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1809                 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1810                 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1811                 verts++;
1812             }
1813         }
1814         helper.recordDraw(target);
1815     }
1816
1817     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1818
1819     RRectEllipseRendererBatch(const Geometry& geometry) : INHERITED(ClassID()) {
1820         fGeoData.push_back(geometry);
1821
1822         this->setBounds(geometry.fDevBounds);
1823     }
1824
1825     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
1826         RRectEllipseRendererBatch* that = t->cast<RRectEllipseRendererBatch>();
1827
1828         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1829                                     that->bounds(), caps)) {
1830             return false;
1831         }
1832
1833         // TODO use vertex color to avoid breaking batches
1834         if (this->color() != that->color()) {
1835             return false;
1836         }
1837
1838         if (this->stroke() != that->stroke()) {
1839             return false;
1840         }
1841
1842         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1843         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1844             return false;
1845         }
1846
1847         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1848         this->joinBounds(that->bounds());
1849         return true;
1850     }
1851
1852     GrColor color() const { return fBatch.fColor; }
1853     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1854     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1855     bool stroke() const { return fBatch.fStroke; }
1856
1857     struct BatchTracker {
1858         GrColor fColor;
1859         bool fStroke;
1860         bool fUsesLocalCoords;
1861         bool fColorIgnored;
1862         bool fCoverageIgnored;
1863     };
1864
1865     BatchTracker fBatch;
1866     SkSTArray<1, Geometry, true> fGeoData;
1867
1868     typedef GrVertexBatch INHERITED;
1869 };
1870
1871 static GrDrawBatch* create_rrect_batch(GrColor color,
1872                                        const SkMatrix& viewMatrix,
1873                                        const SkRRect& rrect,
1874                                        const SkStrokeRec& stroke) {
1875     SkASSERT(viewMatrix.rectStaysRect());
1876     SkASSERT(rrect.isSimple());
1877     SkASSERT(!rrect.isOval());
1878
1879     // RRect batchs only handle simple, but not too simple, rrects
1880     // do any matrix crunching before we reset the draw state for device coords
1881     const SkRect& rrectBounds = rrect.getBounds();
1882     SkRect bounds;
1883     viewMatrix.mapRect(&bounds, rrectBounds);
1884
1885     SkVector radii = rrect.getSimpleRadii();
1886     SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX +
1887                                    viewMatrix[SkMatrix::kMSkewY]*radii.fY);
1888     SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX +
1889                                    viewMatrix[SkMatrix::kMScaleY]*radii.fY);
1890
1891     SkStrokeRec::Style style = stroke.getStyle();
1892
1893     // do (potentially) anisotropic mapping of stroke
1894     SkVector scaledStroke;
1895     SkScalar strokeWidth = stroke.getWidth();
1896
1897     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1898                         SkStrokeRec::kHairline_Style == style;
1899     bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
1900
1901     if (hasStroke) {
1902         if (SkStrokeRec::kHairline_Style == style) {
1903             scaledStroke.set(1, 1);
1904         } else {
1905             scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
1906                                                        viewMatrix[SkMatrix::kMSkewY]));
1907             scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
1908                                                        viewMatrix[SkMatrix::kMScaleY]));
1909         }
1910
1911         // if half of strokewidth is greater than radius, we don't handle that right now
1912         if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) {
1913             return nullptr;
1914         }
1915     }
1916
1917     // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
1918     // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
1919     // patch will have fractional coverage. This only matters when the interior is actually filled.
1920     // We could consider falling back to rect rendering here, since a tiny radius is
1921     // indistinguishable from a square corner.
1922     if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
1923         return nullptr;
1924     }
1925
1926     // if the corners are circles, use the circle renderer
1927     if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
1928         SkScalar innerRadius = 0.0f;
1929         SkScalar outerRadius = xRadius;
1930         SkScalar halfWidth = 0;
1931         if (hasStroke) {
1932             if (SkScalarNearlyZero(scaledStroke.fX)) {
1933                 halfWidth = SK_ScalarHalf;
1934             } else {
1935                 halfWidth = SkScalarHalf(scaledStroke.fX);
1936             }
1937
1938             if (isStrokeOnly) {
1939                 innerRadius = xRadius - halfWidth;
1940             }
1941             outerRadius += halfWidth;
1942             bounds.outset(halfWidth, halfWidth);
1943         }
1944
1945         isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
1946
1947         // The radii are outset for two reasons. First, it allows the shader to simply perform
1948         // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
1949         // Second, the outer radius is used to compute the verts of the bounding box that is
1950         // rendered and the outset ensures the box will cover all partially covered by the rrect
1951         // corners.
1952         outerRadius += SK_ScalarHalf;
1953         innerRadius -= SK_ScalarHalf;
1954
1955         // Expand the rect so all the pixels will be captured.
1956         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1957
1958         RRectCircleRendererBatch::Geometry geometry;
1959         geometry.fViewMatrix = viewMatrix;
1960         geometry.fColor = color;
1961         geometry.fInnerRadius = innerRadius;
1962         geometry.fOuterRadius = outerRadius;
1963         geometry.fStroke = isStrokeOnly;
1964         geometry.fDevBounds = bounds;
1965
1966         return RRectCircleRendererBatch::Create(geometry);
1967     // otherwise we use the ellipse renderer
1968     } else {
1969         SkScalar innerXRadius = 0.0f;
1970         SkScalar innerYRadius = 0.0f;
1971         if (hasStroke) {
1972             if (SkScalarNearlyZero(scaledStroke.length())) {
1973                 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1974             } else {
1975                 scaledStroke.scale(SK_ScalarHalf);
1976             }
1977
1978             // we only handle thick strokes for near-circular ellipses
1979             if (scaledStroke.length() > SK_ScalarHalf &&
1980                 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
1981                 return nullptr;
1982             }
1983
1984             // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1985             if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
1986                 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
1987                 return nullptr;
1988             }
1989
1990             // this is legit only if scale & translation (which should be the case at the moment)
1991             if (isStrokeOnly) {
1992                 innerXRadius = xRadius - scaledStroke.fX;
1993                 innerYRadius = yRadius - scaledStroke.fY;
1994             }
1995
1996             xRadius += scaledStroke.fX;
1997             yRadius += scaledStroke.fY;
1998             bounds.outset(scaledStroke.fX, scaledStroke.fY);
1999         }
2000
2001         isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
2002
2003         // Expand the rect so all the pixels will be captured.
2004         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
2005
2006         RRectEllipseRendererBatch::Geometry geometry;
2007         geometry.fViewMatrix = viewMatrix;
2008         geometry.fColor = color;
2009         geometry.fXRadius = xRadius;
2010         geometry.fYRadius = yRadius;
2011         geometry.fInnerXRadius = innerXRadius;
2012         geometry.fInnerYRadius = innerYRadius;
2013         geometry.fStroke = isStrokeOnly;
2014         geometry.fDevBounds = bounds;
2015
2016         return RRectEllipseRendererBatch::Create(geometry);
2017     }
2018 }
2019
2020 bool GrOvalRenderer::DrawRRect(GrDrawTarget* target,
2021                                const GrPipelineBuilder& pipelineBuilder,
2022                                GrColor color,
2023                                const SkMatrix& viewMatrix,
2024                                bool useAA,
2025                                const SkRRect& rrect,
2026                                const SkStrokeRec& stroke) {
2027     if (rrect.isOval()) {
2028         return DrawOval(target, pipelineBuilder, color, viewMatrix, useAA, rrect.getBounds(),
2029                         stroke);
2030     }
2031
2032     bool useCoverageAA = useAA && !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
2033
2034     // only anti-aliased rrects for now
2035     if (!useCoverageAA) {
2036         return false;
2037     }
2038
2039     if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
2040         return false;
2041     }
2042
2043     SkAutoTUnref<GrDrawBatch> batch(create_rrect_batch(color, viewMatrix, rrect, stroke));
2044     if (!batch) {
2045         return false;
2046     }
2047
2048     target->drawBatch(pipelineBuilder, batch);
2049     return true;
2050 }
2051
2052 ///////////////////////////////////////////////////////////////////////////////////////////////////
2053
2054 #ifdef GR_TEST_UTILS
2055
2056 DRAW_BATCH_TEST_DEFINE(CircleBatch) {
2057     SkMatrix viewMatrix = GrTest::TestMatrix(random);
2058     GrColor color = GrRandomColor(random);
2059     bool useCoverageAA = random->nextBool();
2060     SkRect circle = GrTest::TestSquare(random);
2061     return create_circle_batch(color, viewMatrix, useCoverageAA, circle,
2062                                GrTest::TestStrokeRec(random));
2063 }
2064
2065 DRAW_BATCH_TEST_DEFINE(EllipseBatch) {
2066     SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
2067     GrColor color = GrRandomColor(random);
2068     SkRect ellipse = GrTest::TestSquare(random);
2069     return create_ellipse_batch(color, viewMatrix, true, ellipse,
2070                                 GrTest::TestStrokeRec(random));
2071 }
2072
2073 DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) {
2074     SkMatrix viewMatrix = GrTest::TestMatrix(random);
2075     GrColor color = GrRandomColor(random);
2076     bool useCoverageAA = random->nextBool();
2077     SkRect ellipse = GrTest::TestSquare(random);
2078     return create_diellipse_batch(color, viewMatrix, useCoverageAA, ellipse,
2079                                   GrTest::TestStrokeRec(random));
2080 }
2081
2082 DRAW_BATCH_TEST_DEFINE(RRectBatch) {
2083     SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
2084     GrColor color = GrRandomColor(random);
2085     const SkRRect& rrect = GrTest::TestRRectSimple(random);
2086     return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(random));
2087 }
2088
2089 #endif