• Home
  • History
  • Annotate
  • 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 "gl/builders/GrGLProgramBuilder.h"
9 #include "GrOvalEffect.h"
10 
11 #include "gl/GrGLProcessor.h"
12 #include "gl/GrGLSL.h"
13 #include "GrTBackendProcessorFactory.h"
14 
15 #include "SkRect.h"
16 
17 //////////////////////////////////////////////////////////////////////////////
18 
19 class GLCircleEffect;
20 
21 class CircleEffect : public GrFragmentProcessor {
22 public:
23     static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius);
24 
~CircleEffect()25     virtual ~CircleEffect() {};
Name()26     static const char* Name() { return "Circle"; }
27 
getCenter() const28     const SkPoint& getCenter() const { return fCenter; }
getRadius() const29     SkScalar getRadius() const { return fRadius; }
30 
getEdgeType() const31     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
32 
33     typedef GLCircleEffect GLProcessor;
34 
35     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
36 
37     virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
38 
39 private:
40     CircleEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius);
41 
42     virtual bool onIsEqual(const GrProcessor&) const SK_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 
Create(GrPrimitiveEdgeType edgeType,const SkPoint & center,SkScalar radius)53 GrFragmentProcessor* CircleEffect::Create(GrPrimitiveEdgeType edgeType, const SkPoint& center,
54                                           SkScalar radius) {
55     SkASSERT(radius >= 0);
56     return SkNEW_ARGS(CircleEffect, (edgeType, center, radius));
57 }
58 
getConstantColorComponents(GrColor * color,uint32_t * validFlags) const59 void CircleEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
60     *validFlags = 0;
61 }
62 
getFactory() const63 const GrBackendFragmentProcessorFactory& CircleEffect::getFactory() const {
64     return GrTBackendFragmentProcessorFactory<CircleEffect>::getInstance();
65 }
66 
CircleEffect(GrPrimitiveEdgeType edgeType,const SkPoint & c,SkScalar r)67 CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r)
68     : fCenter(c)
69     , fRadius(r)
70     , fEdgeType(edgeType) {
71     this->setWillReadFragmentPosition();
72 }
73 
onIsEqual(const GrProcessor & other) const74 bool CircleEffect::onIsEqual(const GrProcessor& other) const {
75     const CircleEffect& ce = other.cast<CircleEffect>();
76     return fEdgeType == ce.fEdgeType && fCenter == ce.fCenter && fRadius == ce.fRadius;
77 }
78 
79 //////////////////////////////////////////////////////////////////////////////
80 
81 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleEffect);
82 
TestCreate(SkRandom * random,GrContext *,const GrDrawTargetCaps & caps,GrTexture * [])83 GrFragmentProcessor* CircleEffect::TestCreate(SkRandom* random,
84                                               GrContext*,
85                                               const GrDrawTargetCaps& caps,
86                                               GrTexture*[]) {
87     SkPoint center;
88     center.fX = random->nextRangeScalar(0.f, 1000.f);
89     center.fY = random->nextRangeScalar(0.f, 1000.f);
90     SkScalar radius = random->nextRangeF(0.f, 1000.f);
91     GrPrimitiveEdgeType et;
92     do {
93         et = (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt);
94     } while (kHairlineAA_GrProcessorEdgeType == et);
95     return CircleEffect::Create(et, center, radius);
96 }
97 
98 //////////////////////////////////////////////////////////////////////////////
99 
100 class GLCircleEffect : public GrGLFragmentProcessor {
101 public:
102     GLCircleEffect(const GrBackendProcessorFactory&, const GrProcessor&);
103 
104     virtual void emitCode(GrGLProgramBuilder* builder,
105                           const GrFragmentProcessor& fp,
106                           const GrProcessorKey& key,
107                           const char* outputColor,
108                           const char* inputColor,
109                           const TransformedCoordsArray&,
110                           const TextureSamplerArray&) SK_OVERRIDE;
111 
112     static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
113 
114     virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
115 
116 private:
117     GrGLProgramDataManager::UniformHandle fCircleUniform;
118     SkPoint                               fPrevCenter;
119     SkScalar                              fPrevRadius;
120 
121     typedef GrGLFragmentProcessor INHERITED;
122 };
123 
GLCircleEffect(const GrBackendProcessorFactory & factory,const GrProcessor &)124 GLCircleEffect::GLCircleEffect(const GrBackendProcessorFactory& factory,
125                                const GrProcessor&)
126     : INHERITED (factory) {
127     fPrevRadius = -1.f;
128 }
129 
emitCode(GrGLProgramBuilder * builder,const GrFragmentProcessor & fp,const GrProcessorKey & key,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)130 void GLCircleEffect::emitCode(GrGLProgramBuilder* builder,
131                               const GrFragmentProcessor& fp,
132                               const GrProcessorKey& key,
133                               const char* outputColor,
134                               const char* inputColor,
135                               const TransformedCoordsArray&,
136                               const TextureSamplerArray& samplers) {
137     const CircleEffect& ce = fp.cast<CircleEffect>();
138     const char *circleName;
139     // The circle uniform is (center.x, center.y, radius + 0.5) for regular fills and
140     // (... ,radius - 0.5) for inverse fills.
141     fCircleUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
142                                          kVec3f_GrSLType,
143                                          "circle",
144                                          &circleName);
145 
146     GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
147     const char* fragmentPos = fsBuilder->fragmentPosition();
148 
149     SkASSERT(kHairlineAA_GrProcessorEdgeType != ce.getEdgeType());
150     if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) {
151         fsBuilder->codeAppendf("\t\tfloat d = length(%s.xy - %s.xy) - %s.z;\n",
152                                 circleName, fragmentPos, circleName);
153     } else {
154         fsBuilder->codeAppendf("\t\tfloat d = %s.z - length(%s.xy - %s.xy);\n",
155                                circleName, fragmentPos, circleName);
156     }
157     if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) {
158         fsBuilder->codeAppend("\t\td = clamp(d, 0.0, 1.0);\n");
159     } else {
160         fsBuilder->codeAppend("\t\td = d > 0.5 ? 1.0 : 0.0;\n");
161     }
162 
163     fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
164                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("d")).c_str());
165 }
166 
GenKey(const GrProcessor & processor,const GrGLCaps &,GrProcessorKeyBuilder * b)167 void GLCircleEffect::GenKey(const GrProcessor& processor, const GrGLCaps&,
168                             GrProcessorKeyBuilder* b) {
169     const CircleEffect& ce = processor.cast<CircleEffect>();
170     b->add32(ce.getEdgeType());
171 }
172 
setData(const GrGLProgramDataManager & pdman,const GrProcessor & processor)173 void GLCircleEffect::setData(const GrGLProgramDataManager& pdman, const GrProcessor& processor) {
174     const CircleEffect& ce = processor.cast<CircleEffect>();
175     if (ce.getRadius() != fPrevRadius || ce.getCenter() != fPrevCenter) {
176         SkScalar radius = ce.getRadius();
177         if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) {
178             radius -= 0.5f;
179         } else {
180             radius += 0.5f;
181         }
182         pdman.set3f(fCircleUniform, ce.getCenter().fX, ce.getCenter().fY, radius);
183         fPrevCenter = ce.getCenter();
184         fPrevRadius = ce.getRadius();
185     }
186 }
187 
188 //////////////////////////////////////////////////////////////////////////////
189 
190 class GLEllipseEffect;
191 
192 class EllipseEffect : public GrFragmentProcessor {
193 public:
194     static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx,
195                                        SkScalar ry);
196 
~EllipseEffect()197     virtual ~EllipseEffect() {};
Name()198     static const char* Name() { return "Ellipse"; }
199 
getCenter() const200     const SkPoint& getCenter() const { return fCenter; }
getRadii() const201     SkVector getRadii() const { return fRadii; }
202 
getEdgeType() const203     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
204 
205     typedef GLEllipseEffect GLProcessor;
206 
207     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
208 
209     virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
210 
211 private:
212     EllipseEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry);
213 
214     virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE;
215 
216     SkPoint             fCenter;
217     SkVector            fRadii;
218     GrPrimitiveEdgeType    fEdgeType;
219 
220     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
221 
222     typedef GrFragmentProcessor INHERITED;
223 };
224 
Create(GrPrimitiveEdgeType edgeType,const SkPoint & center,SkScalar rx,SkScalar ry)225 GrFragmentProcessor* EllipseEffect::Create(GrPrimitiveEdgeType edgeType,
226                                            const SkPoint& center,
227                                            SkScalar rx,
228                                            SkScalar ry) {
229     SkASSERT(rx >= 0 && ry >= 0);
230     return SkNEW_ARGS(EllipseEffect, (edgeType, center, rx, ry));
231 }
232 
getConstantColorComponents(GrColor * color,uint32_t * validFlags) const233 void EllipseEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
234     *validFlags = 0;
235 }
236 
getFactory() const237 const GrBackendFragmentProcessorFactory& EllipseEffect::getFactory() const {
238     return GrTBackendFragmentProcessorFactory<EllipseEffect>::getInstance();
239 }
240 
EllipseEffect(GrPrimitiveEdgeType edgeType,const SkPoint & c,SkScalar rx,SkScalar ry)241 EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx, SkScalar ry)
242     : fCenter(c)
243     , fRadii(SkVector::Make(rx, ry))
244     , fEdgeType(edgeType) {
245     this->setWillReadFragmentPosition();
246 }
247 
onIsEqual(const GrProcessor & other) const248 bool EllipseEffect::onIsEqual(const GrProcessor& other) const {
249     const EllipseEffect& ee = other.cast<EllipseEffect>();
250     return fEdgeType == ee.fEdgeType && fCenter == ee.fCenter && fRadii == ee.fRadii;
251 }
252 
253 //////////////////////////////////////////////////////////////////////////////
254 
255 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect);
256 
TestCreate(SkRandom * random,GrContext *,const GrDrawTargetCaps & caps,GrTexture * [])257 GrFragmentProcessor* EllipseEffect::TestCreate(SkRandom* random,
258                                                GrContext*,
259                                                const GrDrawTargetCaps& caps,
260                                                GrTexture*[]) {
261     SkPoint center;
262     center.fX = random->nextRangeScalar(0.f, 1000.f);
263     center.fY = random->nextRangeScalar(0.f, 1000.f);
264     SkScalar rx = random->nextRangeF(0.f, 1000.f);
265     SkScalar ry = random->nextRangeF(0.f, 1000.f);
266     GrPrimitiveEdgeType et;
267     do {
268         et = (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt);
269     } while (kHairlineAA_GrProcessorEdgeType == et);
270     return EllipseEffect::Create(et, center, rx, ry);
271 }
272 
273 //////////////////////////////////////////////////////////////////////////////
274 
275 class GLEllipseEffect : public GrGLFragmentProcessor {
276 public:
277     GLEllipseEffect(const GrBackendProcessorFactory&, const GrProcessor&);
278 
279     virtual void emitCode(GrGLProgramBuilder* builder,
280                           const GrFragmentProcessor& fp,
281                           const GrProcessorKey& key,
282                           const char* outputColor,
283                           const char* inputColor,
284                           const TransformedCoordsArray&,
285                           const TextureSamplerArray&) SK_OVERRIDE;
286 
287     static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
288 
289     virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
290 
291 private:
292     GrGLProgramDataManager::UniformHandle fEllipseUniform;
293     SkPoint                               fPrevCenter;
294     SkVector                              fPrevRadii;
295 
296     typedef GrGLFragmentProcessor INHERITED;
297 };
298 
GLEllipseEffect(const GrBackendProcessorFactory & factory,const GrProcessor & effect)299 GLEllipseEffect::GLEllipseEffect(const GrBackendProcessorFactory& factory,
300                                  const GrProcessor& effect)
301     : INHERITED (factory) {
302     fPrevRadii.fX = -1.f;
303 }
304 
emitCode(GrGLProgramBuilder * builder,const GrFragmentProcessor & fp,const GrProcessorKey & key,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)305 void GLEllipseEffect::emitCode(GrGLProgramBuilder* builder,
306                                const GrFragmentProcessor& fp,
307                                const GrProcessorKey& key,
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,
317                                          "ellipse",
318                                          &ellipseName);
319 
320     GrGLFragmentShaderBuilder* 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 GrGLCaps &,GrProcessorKeyBuilder * b)355 void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrGLCaps&,
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 
Create(GrPrimitiveEdgeType edgeType,const SkRect & oval)374 GrFragmentProcessor* GrOvalEffect::Create(GrPrimitiveEdgeType edgeType, const SkRect& oval) {
375     if (kHairlineAA_GrProcessorEdgeType == edgeType) {
376         return NULL;
377     }
378     SkScalar w = oval.width();
379     SkScalar h = oval.height();
380     if (SkScalarNearlyEqual(w, h)) {
381         w /= 2;
382         return CircleEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), w);
383     } else {
384         w /= 2;
385         h /= 2;
386         return EllipseEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), w, h);
387     }
388 
389     return NULL;
390 }
391