GrOvalEffect.cpp revision 0e08fc17e4718f7ce4e38f793695896473e96948
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
19class GLCircleEffect;
20
21class CircleEffect : public GrFragmentProcessor {
22public:
23    static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius);
24
25    virtual ~CircleEffect() {};
26    static const char* Name() { return "Circle"; }
27
28    const SkPoint& getCenter() const { return fCenter; }
29    SkScalar getRadius() const { return fRadius; }
30
31    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
32
33    typedef GLCircleEffect GLProcessor;
34
35    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
36
37private:
38    CircleEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius);
39
40    virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
41
42    virtual void onComputeInvariantOutput(InvariantOutput* inout) 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
53GrFragmentProcessor* CircleEffect::Create(GrPrimitiveEdgeType edgeType, const SkPoint& center,
54                                          SkScalar radius) {
55    SkASSERT(radius >= 0);
56    return SkNEW_ARGS(CircleEffect, (edgeType, center, radius));
57}
58
59void CircleEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
60    inout->mulByUnknownAlpha();
61}
62
63const GrBackendFragmentProcessorFactory& CircleEffect::getFactory() const {
64    return GrTBackendFragmentProcessorFactory<CircleEffect>::getInstance();
65}
66
67CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r)
68    : fCenter(c)
69    , fRadius(r)
70    , fEdgeType(edgeType) {
71    this->setWillReadFragmentPosition();
72}
73
74bool CircleEffect::onIsEqual(const GrFragmentProcessor& other) const {
75    const CircleEffect& ce = other.cast<CircleEffect>();
76    return fEdgeType == ce.fEdgeType && fCenter == ce.fCenter && fRadius == ce.fRadius;
77}
78
79//////////////////////////////////////////////////////////////////////////////
80
81GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleEffect);
82
83GrFragmentProcessor* 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
100class GLCircleEffect : public GrGLFragmentProcessor {
101public:
102    GLCircleEffect(const GrBackendProcessorFactory&, const GrProcessor&);
103
104    virtual void emitCode(GrGLFPBuilder* 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
116private:
117    GrGLProgramDataManager::UniformHandle fCircleUniform;
118    SkPoint                               fPrevCenter;
119    SkScalar                              fPrevRadius;
120
121    typedef GrGLFragmentProcessor INHERITED;
122};
123
124GLCircleEffect::GLCircleEffect(const GrBackendProcessorFactory& factory,
125                               const GrProcessor&)
126    : INHERITED (factory) {
127    fPrevRadius = -1.f;
128}
129
130void GLCircleEffect::emitCode(GrGLFPBuilder* 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    GrGLFPFragmentBuilder* 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
167void GLCircleEffect::GenKey(const GrProcessor& processor, const GrGLCaps&,
168                            GrProcessorKeyBuilder* b) {
169    const CircleEffect& ce = processor.cast<CircleEffect>();
170    b->add32(ce.getEdgeType());
171}
172
173void 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
190class GLEllipseEffect;
191
192class EllipseEffect : public GrFragmentProcessor {
193public:
194    static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx,
195                                       SkScalar ry);
196
197    virtual ~EllipseEffect() {};
198    static const char* Name() { return "Ellipse"; }
199
200    const SkPoint& getCenter() const { return fCenter; }
201    SkVector getRadii() const { return fRadii; }
202
203    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
204
205    typedef GLEllipseEffect GLProcessor;
206
207    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
208
209private:
210    EllipseEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry);
211
212    virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
213
214    virtual void onComputeInvariantOutput(InvariantOutput* inout) 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
225GrFragmentProcessor* 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
233void EllipseEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
234    inout->mulByUnknownAlpha();
235}
236
237const GrBackendFragmentProcessorFactory& EllipseEffect::getFactory() const {
238    return GrTBackendFragmentProcessorFactory<EllipseEffect>::getInstance();
239}
240
241EllipseEffect::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
248bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
249    const EllipseEffect& ee = other.cast<EllipseEffect>();
250    return fEdgeType == ee.fEdgeType && fCenter == ee.fCenter && fRadii == ee.fRadii;
251}
252
253//////////////////////////////////////////////////////////////////////////////
254
255GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect);
256
257GrFragmentProcessor* 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
275class GLEllipseEffect : public GrGLFragmentProcessor {
276public:
277    GLEllipseEffect(const GrBackendProcessorFactory&, const GrProcessor&);
278
279    virtual void emitCode(GrGLFPBuilder* 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
291private:
292    GrGLProgramDataManager::UniformHandle fEllipseUniform;
293    SkPoint                               fPrevCenter;
294    SkVector                              fPrevRadii;
295
296    typedef GrGLFragmentProcessor INHERITED;
297};
298
299GLEllipseEffect::GLEllipseEffect(const GrBackendProcessorFactory& factory,
300                                 const GrProcessor& effect)
301    : INHERITED (factory) {
302    fPrevRadii.fX = -1.f;
303}
304
305void GLEllipseEffect::emitCode(GrGLFPBuilder* 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    GrGLFPFragmentBuilder* 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
355void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrGLCaps&,
356                             GrProcessorKeyBuilder* b) {
357    const EllipseEffect& ee = effect.cast<EllipseEffect>();
358    b->add32(ee.getEdgeType());
359}
360
361void 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
374GrFragmentProcessor* 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