1 /*
2  * Copyright 2014 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 "GrOvalEffect.h"
9 
10 #include "GrFragmentProcessor.h"
11 #include "SkRect.h"
12 #include "GrShaderCaps.h"
13 #include "glsl/GrGLSLFragmentProcessor.h"
14 #include "glsl/GrGLSLFragmentShaderBuilder.h"
15 #include "glsl/GrGLSLProgramDataManager.h"
16 #include "glsl/GrGLSLUniformHandler.h"
17 #include "../private/GrGLSL.h"
18 
19 //////////////////////////////////////////////////////////////////////////////
20 
21 class CircleEffect : public GrFragmentProcessor {
22 public:
23     static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, const SkPoint& center,
24                                            SkScalar radius);
25 
~CircleEffect()26     ~CircleEffect() override {}
27 
name() const28     const char* name() const override { return "Circle"; }
29 
getCenter() const30     const SkPoint& getCenter() const { return fCenter; }
getRadius() const31     SkScalar getRadius() const { return fRadius; }
32 
getEdgeType() const33     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
34 
35 private:
36     CircleEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius);
37 
38     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
39 
40     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
41 
42     bool onIsEqual(const GrFragmentProcessor&) const override;
43 
44     SkPoint             fCenter;
45     SkScalar            fRadius;
46     GrPrimitiveEdgeType    fEdgeType;
47 
48     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
49 
50     typedef GrFragmentProcessor INHERITED;
51 };
52 
Make(GrPrimitiveEdgeType edgeType,const SkPoint & center,SkScalar radius)53 sk_sp<GrFragmentProcessor> CircleEffect::Make(GrPrimitiveEdgeType edgeType, const SkPoint& center,
54                                               SkScalar radius) {
55     SkASSERT(radius >= 0);
56     return sk_sp<GrFragmentProcessor>(new CircleEffect(edgeType, center, radius));
57 }
58 
CircleEffect(GrPrimitiveEdgeType edgeType,const SkPoint & c,SkScalar r)59 CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r)
60         : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
61         , fCenter(c)
62         , fRadius(r)
63         , fEdgeType(edgeType) {
64     this->initClassID<CircleEffect>();
65 }
66 
onIsEqual(const GrFragmentProcessor & other) const67 bool CircleEffect::onIsEqual(const GrFragmentProcessor& other) const {
68     const CircleEffect& ce = other.cast<CircleEffect>();
69     return fEdgeType == ce.fEdgeType && fCenter == ce.fCenter && fRadius == ce.fRadius;
70 }
71 
72 //////////////////////////////////////////////////////////////////////////////
73 
74 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleEffect);
75 
76 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)77 sk_sp<GrFragmentProcessor> CircleEffect::TestCreate(GrProcessorTestData* d) {
78     SkPoint center;
79     center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f);
80     center.fY = d->fRandom->nextRangeScalar(0.f, 1000.f);
81     SkScalar radius = d->fRandom->nextRangeF(0.f, 1000.f);
82     GrPrimitiveEdgeType et;
83     do {
84         et = (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt);
85     } while (kHairlineAA_GrProcessorEdgeType == et);
86     return CircleEffect::Make(et, center, radius);
87 }
88 #endif
89 
90 //////////////////////////////////////////////////////////////////////////////
91 
92 class GLCircleEffect : public GrGLSLFragmentProcessor {
93 public:
GLCircleEffect()94     GLCircleEffect() : fPrevRadius(-1.0f) { }
95 
96     virtual void emitCode(EmitArgs&) override;
97 
98     static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
99 
100 protected:
101     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
102 
103 private:
104     GrGLSLProgramDataManager::UniformHandle fCircleUniform;
105     SkPoint                                 fPrevCenter;
106     SkScalar                                fPrevRadius;
107 
108     typedef GrGLSLFragmentProcessor INHERITED;
109 };
110 
emitCode(EmitArgs & args)111 void GLCircleEffect::emitCode(EmitArgs& args) {
112     const CircleEffect& ce = args.fFp.cast<CircleEffect>();
113     const char *circleName;
114     // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
115     // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
116     fCircleUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
117                                                       kVec4f_GrSLType, kDefault_GrSLPrecision,
118                                                       "circle",
119                                                       &circleName);
120 
121     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
122 
123     SkASSERT(kHairlineAA_GrProcessorEdgeType != ce.getEdgeType());
124     // TODO: Right now the distance to circle caclulation is performed in a space normalized to the
125     // radius and then denormalized. This is to prevent overflow on devices that have a "real"
126     // mediump. It'd be nice to only to this on mediump devices but we currently don't have the
127     // caps here.
128     if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) {
129         fragBuilder->codeAppendf("float d = (length((%s.xy - sk_FragCoord.xy) * %s.w) - 1.0) * "
130                                             "%s.z;",
131                                  circleName, circleName, circleName);
132     } else {
133         fragBuilder->codeAppendf("float d = (1.0 - length((%s.xy - sk_FragCoord.xy) *  %s.w)) * "
134                                                   "%s.z;",
135                                  circleName, circleName, circleName);
136     }
137     if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) {
138         fragBuilder->codeAppend("d = clamp(d, 0.0, 1.0);");
139     } else {
140         fragBuilder->codeAppend("d = d > 0.5 ? 1.0 : 0.0;");
141     }
142 
143     fragBuilder->codeAppendf("%s = %s;", args.fOutputColor,
144                              (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("d")).c_str());
145 }
146 
GenKey(const GrProcessor & processor,const GrShaderCaps &,GrProcessorKeyBuilder * b)147 void GLCircleEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&,
148                             GrProcessorKeyBuilder* b) {
149     const CircleEffect& ce = processor.cast<CircleEffect>();
150     b->add32(ce.getEdgeType());
151 }
152 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & processor)153 void GLCircleEffect::onSetData(const GrGLSLProgramDataManager& pdman,
154                                const GrProcessor& processor) {
155     const CircleEffect& ce = processor.cast<CircleEffect>();
156     if (ce.getRadius() != fPrevRadius || ce.getCenter() != fPrevCenter) {
157         SkScalar radius = ce.getRadius();
158         if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) {
159             radius -= 0.5f;
160         } else {
161             radius += 0.5f;
162         }
163         pdman.set4f(fCircleUniform, ce.getCenter().fX, ce.getCenter().fY, radius,
164                     SkScalarInvert(radius));
165         fPrevCenter = ce.getCenter();
166         fPrevRadius = ce.getRadius();
167     }
168 }
169 
170 ///////////////////////////////////////////////////////////////////////////////////////////////////
171 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const172 void CircleEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
173                                          GrProcessorKeyBuilder* b) const {
174     GLCircleEffect::GenKey(*this, caps, b);
175 }
176 
onCreateGLSLInstance() const177 GrGLSLFragmentProcessor* CircleEffect::onCreateGLSLInstance() const  {
178     return new GLCircleEffect;
179 }
180 
181 //////////////////////////////////////////////////////////////////////////////
182 
183 class EllipseEffect : public GrFragmentProcessor {
184 public:
185     static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, const SkPoint& center,
186                                            SkScalar rx, SkScalar ry);
187 
~EllipseEffect()188     ~EllipseEffect() override {}
189 
name() const190     const char* name() const override { return "Ellipse"; }
191 
getCenter() const192     const SkPoint& getCenter() const { return fCenter; }
getRadii() const193     SkVector getRadii() const { return fRadii; }
194 
getEdgeType() const195     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
196 
197 private:
198     EllipseEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry);
199 
200     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
201 
202     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
203 
204     bool onIsEqual(const GrFragmentProcessor&) const override;
205 
206     SkPoint             fCenter;
207     SkVector            fRadii;
208     GrPrimitiveEdgeType    fEdgeType;
209 
210     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
211 
212     typedef GrFragmentProcessor INHERITED;
213 };
214 
Make(GrPrimitiveEdgeType edgeType,const SkPoint & center,SkScalar rx,SkScalar ry)215 sk_sp<GrFragmentProcessor> EllipseEffect::Make(GrPrimitiveEdgeType edgeType,
216                                                const SkPoint& center,
217                                                SkScalar rx,
218                                                SkScalar ry) {
219     SkASSERT(rx >= 0 && ry >= 0);
220     return sk_sp<GrFragmentProcessor>(new EllipseEffect(edgeType, center, rx, ry));
221 }
222 
EllipseEffect(GrPrimitiveEdgeType edgeType,const SkPoint & c,SkScalar rx,SkScalar ry)223 EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx,
224                              SkScalar ry)
225         : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
226         , fCenter(c)
227         , fRadii(SkVector::Make(rx, ry))
228         , fEdgeType(edgeType) {
229     this->initClassID<EllipseEffect>();
230 }
231 
onIsEqual(const GrFragmentProcessor & other) const232 bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
233     const EllipseEffect& ee = other.cast<EllipseEffect>();
234     return fEdgeType == ee.fEdgeType && fCenter == ee.fCenter && fRadii == ee.fRadii;
235 }
236 
237 //////////////////////////////////////////////////////////////////////////////
238 
239 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect);
240 
241 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)242 sk_sp<GrFragmentProcessor> EllipseEffect::TestCreate(GrProcessorTestData* d) {
243     SkPoint center;
244     center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f);
245     center.fY = d->fRandom->nextRangeScalar(0.f, 1000.f);
246     SkScalar rx = d->fRandom->nextRangeF(0.f, 1000.f);
247     SkScalar ry = d->fRandom->nextRangeF(0.f, 1000.f);
248     GrPrimitiveEdgeType et;
249     do {
250         et = (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt);
251     } while (kHairlineAA_GrProcessorEdgeType == et);
252     return EllipseEffect::Make(et, center, rx, ry);
253 }
254 #endif
255 
256 //////////////////////////////////////////////////////////////////////////////
257 
258 class GLEllipseEffect : public GrGLSLFragmentProcessor {
259 public:
GLEllipseEffect()260     GLEllipseEffect() {
261         fPrevRadii.fX = -1.0f;
262     }
263 
264     void emitCode(EmitArgs&) override;
265 
266     static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
267 
268 protected:
269     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
270 
271 private:
272     GrGLSLProgramDataManager::UniformHandle fEllipseUniform;
273     GrGLSLProgramDataManager::UniformHandle fScaleUniform;
274     SkPoint                                 fPrevCenter;
275     SkVector                                fPrevRadii;
276 
277     typedef GrGLSLFragmentProcessor INHERITED;
278 };
279 
emitCode(EmitArgs & args)280 void GLEllipseEffect::emitCode(EmitArgs& args) {
281     const EllipseEffect& ee = args.fFp.cast<EllipseEffect>();
282     const char *ellipseName;
283     // The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2)
284     // The last two terms can underflow on mediump, so we use highp.
285     fEllipseUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
286                                                        kVec4f_GrSLType, kHigh_GrSLPrecision,
287                                                        "ellipse",
288                                                        &ellipseName);
289     // If we're on a device with a "real" mediump then we'll do the distance computation in a space
290     // that is normalized by the larger radius. The scale uniform will be scale, 1/scale. The
291     // inverse squared radii uniform values are already in this normalized space. The center is
292     // not.
293     const char* scaleName = nullptr;
294     if (args.fShaderCaps->floatPrecisionVaries()) {
295         fScaleUniform = args.fUniformHandler->addUniform(
296             kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision,
297             "scale", &scaleName);
298     }
299 
300     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
301 
302     // d is the offset to the ellipse center
303     fragBuilder->codeAppendf("vec2 d = sk_FragCoord.xy - %s.xy;", ellipseName);
304     if (scaleName) {
305         fragBuilder->codeAppendf("d *= %s.y;", scaleName);
306     }
307     fragBuilder->codeAppendf("vec2 Z = d * %s.zw;", ellipseName);
308     // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
309     fragBuilder->codeAppend("float implicit = dot(Z, d) - 1.0;");
310     // grad_dot is the squared length of the gradient of the implicit.
311     fragBuilder->codeAppendf("float grad_dot = 4.0 * dot(Z, Z);");
312     // Avoid calling inversesqrt on zero.
313     fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
314     fragBuilder->codeAppendf("float approx_dist = implicit * inversesqrt(grad_dot);");
315     if (scaleName) {
316         fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName);
317     }
318 
319     switch (ee.getEdgeType()) {
320         case kFillAA_GrProcessorEdgeType:
321             fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);");
322             break;
323         case kInverseFillAA_GrProcessorEdgeType:
324             fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);");
325             break;
326         case kFillBW_GrProcessorEdgeType:
327             fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 0.0 : 1.0;");
328             break;
329         case kInverseFillBW_GrProcessorEdgeType:
330             fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 1.0 : 0.0;");
331             break;
332         case kHairlineAA_GrProcessorEdgeType:
333             SkFAIL("Hairline not expected here.");
334     }
335 
336     fragBuilder->codeAppendf("%s = %s;", args.fOutputColor,
337                              (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str());
338 }
339 
GenKey(const GrProcessor & effect,const GrShaderCaps &,GrProcessorKeyBuilder * b)340 void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&,
341                              GrProcessorKeyBuilder* b) {
342     const EllipseEffect& ee = effect.cast<EllipseEffect>();
343     b->add32(ee.getEdgeType());
344 }
345 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & effect)346 void GLEllipseEffect::onSetData(const GrGLSLProgramDataManager& pdman,
347                                 const GrProcessor& effect) {
348     const EllipseEffect& ee = effect.cast<EllipseEffect>();
349     if (ee.getRadii() != fPrevRadii || ee.getCenter() != fPrevCenter) {
350         float invRXSqd;
351         float invRYSqd;
352         // If we're using a scale factor to work around precision issues, choose the larger radius
353         // as the scale factor. The inv radii need to be pre-adjusted by the scale factor.
354         if (fScaleUniform.isValid()) {
355             if (ee.getRadii().fX > ee.getRadii().fY) {
356                 invRXSqd = 1.f;
357                 invRYSqd = (ee.getRadii().fX * ee.getRadii().fX) /
358                            (ee.getRadii().fY * ee.getRadii().fY);
359                 pdman.set2f(fScaleUniform, ee.getRadii().fX, 1.f / ee.getRadii().fX);
360             } else {
361                 invRXSqd = (ee.getRadii().fY * ee.getRadii().fY) /
362                            (ee.getRadii().fX * ee.getRadii().fX);
363                 invRYSqd = 1.f;
364                 pdman.set2f(fScaleUniform, ee.getRadii().fY, 1.f / ee.getRadii().fY);
365             }
366         } else {
367             invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX);
368             invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY);
369         }
370         pdman.set4f(fEllipseUniform, ee.getCenter().fX, ee.getCenter().fY, invRXSqd, invRYSqd);
371         fPrevCenter = ee.getCenter();
372         fPrevRadii = ee.getRadii();
373     }
374 }
375 
376 ///////////////////////////////////////////////////////////////////////////////////////////////////
377 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const378 void EllipseEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
379                                           GrProcessorKeyBuilder* b) const {
380     GLEllipseEffect::GenKey(*this, caps, b);
381 }
382 
onCreateGLSLInstance() const383 GrGLSLFragmentProcessor* EllipseEffect::onCreateGLSLInstance() const  {
384     return new GLEllipseEffect;
385 }
386 
387 //////////////////////////////////////////////////////////////////////////////
388 
Make(GrPrimitiveEdgeType edgeType,const SkRect & oval)389 sk_sp<GrFragmentProcessor> GrOvalEffect::Make(GrPrimitiveEdgeType edgeType, const SkRect& oval) {
390     if (kHairlineAA_GrProcessorEdgeType == edgeType) {
391         return nullptr;
392     }
393     SkScalar w = oval.width();
394     SkScalar h = oval.height();
395     if (SkScalarNearlyEqual(w, h)) {
396         w /= 2;
397         return CircleEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), w);
398     } else {
399         w /= 2;
400         h /= 2;
401         return EllipseEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), w, h);
402     }
403 
404     return nullptr;
405 }
406