Line data Source code
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 :
26 0 : ~CircleEffect() override {}
27 :
28 0 : const char* name() const override { return "Circle"; }
29 :
30 0 : const SkPoint& getCenter() const { return fCenter; }
31 0 : SkScalar getRadius() const { return fRadius; }
32 :
33 0 : 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 :
53 0 : sk_sp<GrFragmentProcessor> CircleEffect::Make(GrPrimitiveEdgeType edgeType, const SkPoint& center,
54 : SkScalar radius) {
55 0 : SkASSERT(radius >= 0);
56 0 : return sk_sp<GrFragmentProcessor>(new CircleEffect(edgeType, center, radius));
57 : }
58 :
59 0 : CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r)
60 : : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
61 : , fCenter(c)
62 : , fRadius(r)
63 0 : , fEdgeType(edgeType) {
64 0 : this->initClassID<CircleEffect>();
65 0 : }
66 :
67 0 : bool CircleEffect::onIsEqual(const GrFragmentProcessor& other) const {
68 0 : const CircleEffect& ce = other.cast<CircleEffect>();
69 0 : 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
77 0 : sk_sp<GrFragmentProcessor> CircleEffect::TestCreate(GrProcessorTestData* d) {
78 : SkPoint center;
79 0 : center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f);
80 0 : center.fY = d->fRandom->nextRangeScalar(0.f, 1000.f);
81 0 : SkScalar radius = d->fRandom->nextRangeF(0.f, 1000.f);
82 : GrPrimitiveEdgeType et;
83 0 : do {
84 0 : et = (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt);
85 0 : } while (kHairlineAA_GrProcessorEdgeType == et);
86 0 : return CircleEffect::Make(et, center, radius);
87 : }
88 : #endif
89 :
90 : //////////////////////////////////////////////////////////////////////////////
91 :
92 0 : class GLCircleEffect : public GrGLSLFragmentProcessor {
93 : public:
94 0 : 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 GrFragmentProcessor&) override;
102 :
103 : private:
104 : GrGLSLProgramDataManager::UniformHandle fCircleUniform;
105 : SkPoint fPrevCenter;
106 : SkScalar fPrevRadius;
107 :
108 : typedef GrGLSLFragmentProcessor INHERITED;
109 : };
110 :
111 0 : void GLCircleEffect::emitCode(EmitArgs& args) {
112 0 : 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 0 : fCircleUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
117 : kVec4f_GrSLType, kDefault_GrSLPrecision,
118 : "circle",
119 0 : &circleName);
120 :
121 0 : GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
122 :
123 0 : 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 0 : if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) {
129 0 : fragBuilder->codeAppendf("float d = (length((%s.xy - sk_FragCoord.xy) * %s.w) - 1.0) * "
130 : "%s.z;",
131 0 : circleName, circleName, circleName);
132 : } else {
133 0 : fragBuilder->codeAppendf("float d = (1.0 - length((%s.xy - sk_FragCoord.xy) * %s.w)) * "
134 : "%s.z;",
135 0 : circleName, circleName, circleName);
136 : }
137 0 : if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) {
138 0 : fragBuilder->codeAppend("d = clamp(d, 0.0, 1.0);");
139 : } else {
140 0 : fragBuilder->codeAppend("d = d > 0.5 ? 1.0 : 0.0;");
141 : }
142 :
143 0 : fragBuilder->codeAppendf("%s = %s;", args.fOutputColor,
144 0 : (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("d")).c_str());
145 0 : }
146 :
147 0 : void GLCircleEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&,
148 : GrProcessorKeyBuilder* b) {
149 0 : const CircleEffect& ce = processor.cast<CircleEffect>();
150 0 : b->add32(ce.getEdgeType());
151 0 : }
152 :
153 0 : void GLCircleEffect::onSetData(const GrGLSLProgramDataManager& pdman,
154 : const GrFragmentProcessor& processor) {
155 0 : const CircleEffect& ce = processor.cast<CircleEffect>();
156 0 : if (ce.getRadius() != fPrevRadius || ce.getCenter() != fPrevCenter) {
157 0 : SkScalar radius = ce.getRadius();
158 0 : if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) {
159 0 : radius -= 0.5f;
160 : } else {
161 0 : radius += 0.5f;
162 : }
163 0 : pdman.set4f(fCircleUniform, ce.getCenter().fX, ce.getCenter().fY, radius,
164 0 : SkScalarInvert(radius));
165 0 : fPrevCenter = ce.getCenter();
166 0 : fPrevRadius = ce.getRadius();
167 : }
168 0 : }
169 :
170 : ///////////////////////////////////////////////////////////////////////////////////////////////////
171 :
172 0 : void CircleEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
173 : GrProcessorKeyBuilder* b) const {
174 0 : GLCircleEffect::GenKey(*this, caps, b);
175 0 : }
176 :
177 0 : GrGLSLFragmentProcessor* CircleEffect::onCreateGLSLInstance() const {
178 0 : 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 :
188 0 : ~EllipseEffect() override {}
189 :
190 0 : const char* name() const override { return "Ellipse"; }
191 :
192 0 : const SkPoint& getCenter() const { return fCenter; }
193 0 : SkVector getRadii() const { return fRadii; }
194 :
195 0 : 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 :
215 0 : sk_sp<GrFragmentProcessor> EllipseEffect::Make(GrPrimitiveEdgeType edgeType,
216 : const SkPoint& center,
217 : SkScalar rx,
218 : SkScalar ry) {
219 0 : SkASSERT(rx >= 0 && ry >= 0);
220 0 : return sk_sp<GrFragmentProcessor>(new EllipseEffect(edgeType, center, rx, ry));
221 : }
222 :
223 0 : EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx,
224 0 : SkScalar ry)
225 : : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
226 : , fCenter(c)
227 : , fRadii(SkVector::Make(rx, ry))
228 0 : , fEdgeType(edgeType) {
229 0 : this->initClassID<EllipseEffect>();
230 0 : }
231 :
232 0 : bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
233 0 : const EllipseEffect& ee = other.cast<EllipseEffect>();
234 0 : 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
242 0 : sk_sp<GrFragmentProcessor> EllipseEffect::TestCreate(GrProcessorTestData* d) {
243 : SkPoint center;
244 0 : center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f);
245 0 : center.fY = d->fRandom->nextRangeScalar(0.f, 1000.f);
246 0 : SkScalar rx = d->fRandom->nextRangeF(0.f, 1000.f);
247 0 : SkScalar ry = d->fRandom->nextRangeF(0.f, 1000.f);
248 : GrPrimitiveEdgeType et;
249 0 : do {
250 0 : et = (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt);
251 0 : } while (kHairlineAA_GrProcessorEdgeType == et);
252 0 : return EllipseEffect::Make(et, center, rx, ry);
253 : }
254 : #endif
255 :
256 : //////////////////////////////////////////////////////////////////////////////
257 :
258 0 : class GLEllipseEffect : public GrGLSLFragmentProcessor {
259 : public:
260 0 : GLEllipseEffect() {
261 0 : fPrevRadii.fX = -1.0f;
262 0 : }
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 GrFragmentProcessor&) 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 :
280 0 : void GLEllipseEffect::emitCode(EmitArgs& args) {
281 0 : 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 0 : fEllipseUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
286 : kVec4f_GrSLType, kHigh_GrSLPrecision,
287 : "ellipse",
288 0 : &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 0 : const char* scaleName = nullptr;
294 0 : if (args.fShaderCaps->floatPrecisionVaries()) {
295 0 : fScaleUniform = args.fUniformHandler->addUniform(
296 : kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision,
297 0 : "scale", &scaleName);
298 : }
299 :
300 0 : GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
301 :
302 : // d is the offset to the ellipse center
303 0 : fragBuilder->codeAppendf("vec2 d = sk_FragCoord.xy - %s.xy;", ellipseName);
304 0 : if (scaleName) {
305 0 : fragBuilder->codeAppendf("d *= %s.y;", scaleName);
306 : }
307 0 : fragBuilder->codeAppendf("vec2 Z = d * %s.zw;", ellipseName);
308 : // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
309 0 : fragBuilder->codeAppend("float implicit = dot(Z, d) - 1.0;");
310 : // grad_dot is the squared length of the gradient of the implicit.
311 0 : fragBuilder->codeAppendf("float grad_dot = 4.0 * dot(Z, Z);");
312 : // Avoid calling inversesqrt on zero.
313 0 : fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
314 0 : fragBuilder->codeAppendf("float approx_dist = implicit * inversesqrt(grad_dot);");
315 0 : if (scaleName) {
316 0 : fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName);
317 : }
318 :
319 0 : switch (ee.getEdgeType()) {
320 : case kFillAA_GrProcessorEdgeType:
321 0 : fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);");
322 0 : break;
323 : case kInverseFillAA_GrProcessorEdgeType:
324 0 : fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);");
325 0 : break;
326 : case kFillBW_GrProcessorEdgeType:
327 0 : fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 0.0 : 1.0;");
328 0 : break;
329 : case kInverseFillBW_GrProcessorEdgeType:
330 0 : fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 1.0 : 0.0;");
331 0 : break;
332 : case kHairlineAA_GrProcessorEdgeType:
333 0 : SkFAIL("Hairline not expected here.");
334 : }
335 :
336 0 : fragBuilder->codeAppendf("%s = %s;", args.fOutputColor,
337 0 : (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str());
338 0 : }
339 :
340 0 : void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&,
341 : GrProcessorKeyBuilder* b) {
342 0 : const EllipseEffect& ee = effect.cast<EllipseEffect>();
343 0 : b->add32(ee.getEdgeType());
344 0 : }
345 :
346 0 : void GLEllipseEffect::onSetData(const GrGLSLProgramDataManager& pdman,
347 : const GrFragmentProcessor& effect) {
348 0 : const EllipseEffect& ee = effect.cast<EllipseEffect>();
349 0 : 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 0 : if (fScaleUniform.isValid()) {
355 0 : if (ee.getRadii().fX > ee.getRadii().fY) {
356 0 : invRXSqd = 1.f;
357 0 : invRYSqd = (ee.getRadii().fX * ee.getRadii().fX) /
358 0 : (ee.getRadii().fY * ee.getRadii().fY);
359 0 : pdman.set2f(fScaleUniform, ee.getRadii().fX, 1.f / ee.getRadii().fX);
360 : } else {
361 0 : invRXSqd = (ee.getRadii().fY * ee.getRadii().fY) /
362 0 : (ee.getRadii().fX * ee.getRadii().fX);
363 0 : invRYSqd = 1.f;
364 0 : pdman.set2f(fScaleUniform, ee.getRadii().fY, 1.f / ee.getRadii().fY);
365 : }
366 : } else {
367 0 : invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX);
368 0 : invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY);
369 : }
370 0 : pdman.set4f(fEllipseUniform, ee.getCenter().fX, ee.getCenter().fY, invRXSqd, invRYSqd);
371 0 : fPrevCenter = ee.getCenter();
372 0 : fPrevRadii = ee.getRadii();
373 : }
374 0 : }
375 :
376 : ///////////////////////////////////////////////////////////////////////////////////////////////////
377 :
378 0 : void EllipseEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
379 : GrProcessorKeyBuilder* b) const {
380 0 : GLEllipseEffect::GenKey(*this, caps, b);
381 0 : }
382 :
383 0 : GrGLSLFragmentProcessor* EllipseEffect::onCreateGLSLInstance() const {
384 0 : return new GLEllipseEffect;
385 : }
386 :
387 : //////////////////////////////////////////////////////////////////////////////
388 :
389 0 : sk_sp<GrFragmentProcessor> GrOvalEffect::Make(GrPrimitiveEdgeType edgeType, const SkRect& oval) {
390 0 : if (kHairlineAA_GrProcessorEdgeType == edgeType) {
391 0 : return nullptr;
392 : }
393 0 : SkScalar w = oval.width();
394 0 : SkScalar h = oval.height();
395 0 : if (SkScalarNearlyEqual(w, h)) {
396 0 : w /= 2;
397 0 : return CircleEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), w);
398 : } else {
399 0 : w /= 2;
400 0 : h /= 2;
401 0 : return EllipseEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), w, h);
402 : }
403 :
404 : return nullptr;
405 : }
|