• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrInvariantOutput.h"
12 #include "SkRect.h"
13 #include "gl/GrGLProcessor.h"
14 #include "gl/GrGLSL.h"
15 #include "gl/builders/GrGLProgramBuilder.h"
16 
17 //////////////////////////////////////////////////////////////////////////////
18 
19 class CircleEffect : public GrFragmentProcessor {
20 public:
21     static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius);
22 
~CircleEffect()23     virtual ~CircleEffect() {};
24 
name() const25     const char* name() const override { return "Circle"; }
26 
27     void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
28 
29     GrGLFragmentProcessor* createGLInstance() const override;
30 
getCenter() const31     const SkPoint& getCenter() const { return fCenter; }
getRadius() const32     SkScalar getRadius() const { return fRadius; }
33 
getEdgeType() const34     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
35 
36 private:
37     CircleEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius);
38 
39     bool onIsEqual(const GrFragmentProcessor&) const override;
40 
41     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
42 
43     SkPoint             fCenter;
44     SkScalar            fRadius;
45     GrPrimitiveEdgeType    fEdgeType;
46 
47     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
48 
49     typedef GrFragmentProcessor INHERITED;
50 };
51 
Create(GrPrimitiveEdgeType edgeType,const SkPoint & center,SkScalar radius)52 GrFragmentProcessor* CircleEffect::Create(GrPrimitiveEdgeType edgeType, const SkPoint& center,
53                                           SkScalar radius) {
54     SkASSERT(radius >= 0);
55     return SkNEW_ARGS(CircleEffect, (edgeType, center, radius));
56 }
57 
onComputeInvariantOutput(GrInvariantOutput * inout) const58 void CircleEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
59     inout->mulByUnknownSingleComponent();
60 }
61 
CircleEffect(GrPrimitiveEdgeType edgeType,const SkPoint & c,SkScalar r)62 CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r)
63     : fCenter(c)
64     , fRadius(r)
65     , fEdgeType(edgeType) {
66     this->initClassID<CircleEffect>();
67     this->setWillReadFragmentPosition();
68 }
69 
onIsEqual(const GrFragmentProcessor & other) const70 bool CircleEffect::onIsEqual(const GrFragmentProcessor& other) const {
71     const CircleEffect& ce = other.cast<CircleEffect>();
72     return fEdgeType == ce.fEdgeType && fCenter == ce.fCenter && fRadius == ce.fRadius;
73 }
74 
75 //////////////////////////////////////////////////////////////////////////////
76 
77 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleEffect);
78 
TestCreate(SkRandom * random,GrContext *,const GrDrawTargetCaps & caps,GrTexture * [])79 GrFragmentProcessor* CircleEffect::TestCreate(SkRandom* random,
80                                               GrContext*,
81                                               const GrDrawTargetCaps& caps,
82                                               GrTexture*[]) {
83     SkPoint center;
84     center.fX = random->nextRangeScalar(0.f, 1000.f);
85     center.fY = random->nextRangeScalar(0.f, 1000.f);
86     SkScalar radius = random->nextRangeF(0.f, 1000.f);
87     GrPrimitiveEdgeType et;
88     do {
89         et = (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt);
90     } while (kHairlineAA_GrProcessorEdgeType == et);
91     return CircleEffect::Create(et, center, radius);
92 }
93 
94 //////////////////////////////////////////////////////////////////////////////
95 
96 class GLCircleEffect : public GrGLFragmentProcessor {
97 public:
98     GLCircleEffect(const GrProcessor&);
99 
100     virtual void emitCode(GrGLFPBuilder* builder,
101                           const GrFragmentProcessor& fp,
102                           const char* outputColor,
103                           const char* inputColor,
104                           const TransformedCoordsArray&,
105                           const TextureSamplerArray&) override;
106 
107     static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*);
108 
109     void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
110 
111 private:
112     GrGLProgramDataManager::UniformHandle fCircleUniform;
113     SkPoint                               fPrevCenter;
114     SkScalar                              fPrevRadius;
115 
116     typedef GrGLFragmentProcessor INHERITED;
117 };
118 
GLCircleEffect(const GrProcessor &)119 GLCircleEffect::GLCircleEffect(const GrProcessor&) {
120     fPrevRadius = -1.f;
121 }
122 
emitCode(GrGLFPBuilder * builder,const GrFragmentProcessor & fp,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)123 void GLCircleEffect::emitCode(GrGLFPBuilder* builder,
124                               const GrFragmentProcessor& fp,
125                               const char* outputColor,
126                               const char* inputColor,
127                               const TransformedCoordsArray&,
128                               const TextureSamplerArray& samplers) {
129     const CircleEffect& ce = fp.cast<CircleEffect>();
130     const char *circleName;
131     // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
132     // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
133     fCircleUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
134                                          kVec4f_GrSLType, kDefault_GrSLPrecision,
135                                          "circle",
136                                          &circleName);
137 
138     GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
139     const char* fragmentPos = fsBuilder->fragmentPosition();
140 
141     SkASSERT(kHairlineAA_GrProcessorEdgeType != ce.getEdgeType());
142     // TODO: Right now the distance to circle caclulation is performed in a space normalized to the
143     // radius and then denormalized. This is to prevent overflow on devices that have a "real"
144     // mediump. It'd be nice to only to this on mediump devices but we currently don't have the
145     // caps here.
146     if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) {
147         fsBuilder->codeAppendf("\t\tfloat d = (length((%s.xy - %s.xy) * %s.w) - 1.0) * %s.z;\n",
148                                 circleName, fragmentPos, circleName, circleName);
149     } else {
150         fsBuilder->codeAppendf("\t\tfloat d = (1.0 - length((%s.xy - %s.xy) *  %s.w)) * %s.z;\n",
151                                circleName, fragmentPos, circleName, circleName);
152     }
153     if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) {
154         fsBuilder->codeAppend("\t\td = clamp(d, 0.0, 1.0);\n");
155     } else {
156         fsBuilder->codeAppend("\t\td = d > 0.5 ? 1.0 : 0.0;\n");
157     }
158 
159     fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
160                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("d")).c_str());
161 }
162 
GenKey(const GrProcessor & processor,const GrGLSLCaps &,GrProcessorKeyBuilder * b)163 void GLCircleEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&,
164                             GrProcessorKeyBuilder* b) {
165     const CircleEffect& ce = processor.cast<CircleEffect>();
166     b->add32(ce.getEdgeType());
167 }
168 
setData(const GrGLProgramDataManager & pdman,const GrProcessor & processor)169 void GLCircleEffect::setData(const GrGLProgramDataManager& pdman, const GrProcessor& processor) {
170     const CircleEffect& ce = processor.cast<CircleEffect>();
171     if (ce.getRadius() != fPrevRadius || ce.getCenter() != fPrevCenter) {
172         SkScalar radius = ce.getRadius();
173         if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) {
174             radius -= 0.5f;
175         } else {
176             radius += 0.5f;
177         }
178         pdman.set4f(fCircleUniform, ce.getCenter().fX, ce.getCenter().fY, radius,
179                     SkScalarInvert(radius));
180         fPrevCenter = ce.getCenter();
181         fPrevRadius = ce.getRadius();
182     }
183 }
184 
185 ///////////////////////////////////////////////////////////////////////////////////////////////////
186 
getGLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const187 void CircleEffect::getGLProcessorKey(const GrGLSLCaps& caps,
188                                      GrProcessorKeyBuilder* b) const {
189     GLCircleEffect::GenKey(*this, caps, b);
190 }
191 
createGLInstance() const192 GrGLFragmentProcessor* CircleEffect::createGLInstance() const  {
193     return SkNEW_ARGS(GLCircleEffect, (*this));
194 }
195 
196 //////////////////////////////////////////////////////////////////////////////
197 
198 class EllipseEffect : public GrFragmentProcessor {
199 public:
200     static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx,
201                                        SkScalar ry);
202 
~EllipseEffect()203     virtual ~EllipseEffect() {};
204 
name() const205     const char* name() const override { return "Ellipse"; }
206 
207     void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
208 
209     GrGLFragmentProcessor* createGLInstance() const override;
210 
getCenter() const211     const SkPoint& getCenter() const { return fCenter; }
getRadii() const212     SkVector getRadii() const { return fRadii; }
213 
getEdgeType() const214     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
215 
216 private:
217     EllipseEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry);
218 
219     bool onIsEqual(const GrFragmentProcessor&) const override;
220 
221     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
222 
223     SkPoint             fCenter;
224     SkVector            fRadii;
225     GrPrimitiveEdgeType    fEdgeType;
226 
227     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
228 
229     typedef GrFragmentProcessor INHERITED;
230 };
231 
Create(GrPrimitiveEdgeType edgeType,const SkPoint & center,SkScalar rx,SkScalar ry)232 GrFragmentProcessor* EllipseEffect::Create(GrPrimitiveEdgeType edgeType,
233                                            const SkPoint& center,
234                                            SkScalar rx,
235                                            SkScalar ry) {
236     SkASSERT(rx >= 0 && ry >= 0);
237     return SkNEW_ARGS(EllipseEffect, (edgeType, center, rx, ry));
238 }
239 
onComputeInvariantOutput(GrInvariantOutput * inout) const240 void EllipseEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
241     inout->mulByUnknownSingleComponent();
242 }
243 
EllipseEffect(GrPrimitiveEdgeType edgeType,const SkPoint & c,SkScalar rx,SkScalar ry)244 EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx, SkScalar ry)
245     : fCenter(c)
246     , fRadii(SkVector::Make(rx, ry))
247     , fEdgeType(edgeType) {
248     this->initClassID<EllipseEffect>();
249     this->setWillReadFragmentPosition();
250 }
251 
onIsEqual(const GrFragmentProcessor & other) const252 bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
253     const EllipseEffect& ee = other.cast<EllipseEffect>();
254     return fEdgeType == ee.fEdgeType && fCenter == ee.fCenter && fRadii == ee.fRadii;
255 }
256 
257 //////////////////////////////////////////////////////////////////////////////
258 
259 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect);
260 
TestCreate(SkRandom * random,GrContext *,const GrDrawTargetCaps & caps,GrTexture * [])261 GrFragmentProcessor* EllipseEffect::TestCreate(SkRandom* random,
262                                                GrContext*,
263                                                const GrDrawTargetCaps& caps,
264                                                GrTexture*[]) {
265     SkPoint center;
266     center.fX = random->nextRangeScalar(0.f, 1000.f);
267     center.fY = random->nextRangeScalar(0.f, 1000.f);
268     SkScalar rx = random->nextRangeF(0.f, 1000.f);
269     SkScalar ry = random->nextRangeF(0.f, 1000.f);
270     GrPrimitiveEdgeType et;
271     do {
272         et = (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt);
273     } while (kHairlineAA_GrProcessorEdgeType == et);
274     return EllipseEffect::Create(et, center, rx, ry);
275 }
276 
277 //////////////////////////////////////////////////////////////////////////////
278 
279 class GLEllipseEffect : public GrGLFragmentProcessor {
280 public:
281     GLEllipseEffect(const GrProcessor&);
282 
283     virtual void emitCode(GrGLFPBuilder* builder,
284                           const GrFragmentProcessor& fp,
285                           const char* outputColor,
286                           const char* inputColor,
287                           const TransformedCoordsArray&,
288                           const TextureSamplerArray&) override;
289 
290     static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*);
291 
292     void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
293 
294 private:
295     GrGLProgramDataManager::UniformHandle fEllipseUniform;
296     SkPoint                               fPrevCenter;
297     SkVector                              fPrevRadii;
298 
299     typedef GrGLFragmentProcessor INHERITED;
300 };
301 
GLEllipseEffect(const GrProcessor & effect)302 GLEllipseEffect::GLEllipseEffect(const GrProcessor& effect) {
303     fPrevRadii.fX = -1.f;
304 }
305 
emitCode(GrGLFPBuilder * builder,const GrFragmentProcessor & fp,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)306 void GLEllipseEffect::emitCode(GrGLFPBuilder* builder,
307                                const GrFragmentProcessor& fp,
308                                const char* outputColor,
309                                const char* inputColor,
310                                const TransformedCoordsArray&,
311                                const TextureSamplerArray& samplers) {
312     const EllipseEffect& ee = fp.cast<EllipseEffect>();
313     const char *ellipseName;
314     // The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2)
315     fEllipseUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
316                                          kVec4f_GrSLType, kDefault_GrSLPrecision,
317                                          "ellipse",
318                                          &ellipseName);
319 
320     GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
321     const char* fragmentPos = fsBuilder->fragmentPosition();
322 
323     // d is the offset to the ellipse center
324     fsBuilder->codeAppendf("\t\tvec2 d = %s.xy - %s.xy;\n", fragmentPos, ellipseName);
325     fsBuilder->codeAppendf("\t\tvec2 Z = d * %s.zw;\n", ellipseName);
326     // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
327     fsBuilder->codeAppend("\t\tfloat implicit = dot(Z, d) - 1.0;\n");
328     // grad_dot is the squared length of the gradient of the implicit.
329     fsBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
330     // avoid calling inversesqrt on zero.
331     fsBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
332     fsBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
333 
334     switch (ee.getEdgeType()) {
335         case kFillAA_GrProcessorEdgeType:
336             fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
337             break;
338         case kInverseFillAA_GrProcessorEdgeType:
339             fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
340             break;
341         case kFillBW_GrProcessorEdgeType:
342             fsBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n");
343             break;
344         case kInverseFillBW_GrProcessorEdgeType:
345             fsBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 1.0 : 0.0;\n");
346             break;
347         case kHairlineAA_GrProcessorEdgeType:
348             SkFAIL("Hairline not expected here.");
349     }
350 
351     fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
352                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
353 }
354 
GenKey(const GrProcessor & effect,const GrGLSLCaps &,GrProcessorKeyBuilder * b)355 void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrGLSLCaps&,
356                              GrProcessorKeyBuilder* b) {
357     const EllipseEffect& ee = effect.cast<EllipseEffect>();
358     b->add32(ee.getEdgeType());
359 }
360 
setData(const GrGLProgramDataManager & pdman,const GrProcessor & effect)361 void GLEllipseEffect::setData(const GrGLProgramDataManager& pdman, const GrProcessor& effect) {
362     const EllipseEffect& ee = effect.cast<EllipseEffect>();
363     if (ee.getRadii() != fPrevRadii || ee.getCenter() != fPrevCenter) {
364         SkScalar invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX);
365         SkScalar invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY);
366         pdman.set4f(fEllipseUniform, ee.getCenter().fX, ee.getCenter().fY, invRXSqd, invRYSqd);
367         fPrevCenter = ee.getCenter();
368         fPrevRadii = ee.getRadii();
369     }
370 }
371 
372 ///////////////////////////////////////////////////////////////////////////////////////////////////
373 
getGLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const374 void EllipseEffect::getGLProcessorKey(const GrGLSLCaps& caps,
375                                      GrProcessorKeyBuilder* b) const {
376     GLEllipseEffect::GenKey(*this, caps, b);
377 }
378 
createGLInstance() const379 GrGLFragmentProcessor* EllipseEffect::createGLInstance() const  {
380     return SkNEW_ARGS(GLEllipseEffect, (*this));
381 }
382 
383 //////////////////////////////////////////////////////////////////////////////
384 
Create(GrPrimitiveEdgeType edgeType,const SkRect & oval)385 GrFragmentProcessor* GrOvalEffect::Create(GrPrimitiveEdgeType edgeType, const SkRect& oval) {
386     if (kHairlineAA_GrProcessorEdgeType == edgeType) {
387         return NULL;
388     }
389     SkScalar w = oval.width();
390     SkScalar h = oval.height();
391     if (SkScalarNearlyEqual(w, h)) {
392         w /= 2;
393         return CircleEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), w);
394     } else {
395         w /= 2;
396         h /= 2;
397         return EllipseEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), w, h);
398     }
399 
400     return NULL;
401 }
402