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