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