2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "gl/builders/GrGLProgramBuilder.h"
9 #include "GrOvalEffect.h"
11 #include "gl/GrGLProcessor.h"
12 #include "gl/GrGLSL.h"
13 #include "GrTBackendProcessorFactory.h"
17 //////////////////////////////////////////////////////////////////////////////
21 class CircleEffect : public GrFragmentProcessor {
23 static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius);
25 virtual ~CircleEffect() {};
26 static const char* Name() { return "Circle"; }
28 const SkPoint& getCenter() const { return fCenter; }
29 SkScalar getRadius() const { return fRadius; }
31 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
33 typedef GLCircleEffect GLProcessor;
35 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
38 CircleEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius);
40 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
42 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE;
46 GrPrimitiveEdgeType fEdgeType;
48 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
50 typedef GrFragmentProcessor INHERITED;
53 GrFragmentProcessor* CircleEffect::Create(GrPrimitiveEdgeType edgeType, const SkPoint& center,
55 SkASSERT(radius >= 0);
56 return SkNEW_ARGS(CircleEffect, (edgeType, center, radius));
59 void CircleEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
60 inout->mulByUnknownAlpha();
63 const GrBackendFragmentProcessorFactory& CircleEffect::getFactory() const {
64 return GrTBackendFragmentProcessorFactory<CircleEffect>::getInstance();
67 CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r)
70 , fEdgeType(edgeType) {
71 this->setWillReadFragmentPosition();
74 bool CircleEffect::onIsEqual(const GrFragmentProcessor& other) const {
75 const CircleEffect& ce = other.cast<CircleEffect>();
76 return fEdgeType == ce.fEdgeType && fCenter == ce.fCenter && fRadius == ce.fRadius;
79 //////////////////////////////////////////////////////////////////////////////
81 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleEffect);
83 GrFragmentProcessor* CircleEffect::TestCreate(SkRandom* random,
85 const GrDrawTargetCaps& caps,
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;
93 et = (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt);
94 } while (kHairlineAA_GrProcessorEdgeType == et);
95 return CircleEffect::Create(et, center, radius);
98 //////////////////////////////////////////////////////////////////////////////
100 class GLCircleEffect : public GrGLFragmentProcessor {
102 GLCircleEffect(const GrBackendProcessorFactory&, const GrProcessor&);
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;
112 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
114 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
117 GrGLProgramDataManager::UniformHandle fCircleUniform;
119 SkScalar fPrevRadius;
121 typedef GrGLFragmentProcessor INHERITED;
124 GLCircleEffect::GLCircleEffect(const GrBackendProcessorFactory& factory,
126 : INHERITED (factory) {
130 void 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,
146 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
147 const char* fragmentPos = fsBuilder->fragmentPosition();
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);
154 fsBuilder->codeAppendf("\t\tfloat d = %s.z - length(%s.xy - %s.xy);\n",
155 circleName, fragmentPos, circleName);
157 if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) {
158 fsBuilder->codeAppend("\t\td = clamp(d, 0.0, 1.0);\n");
160 fsBuilder->codeAppend("\t\td = d > 0.5 ? 1.0 : 0.0;\n");
163 fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
164 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("d")).c_str());
167 void GLCircleEffect::GenKey(const GrProcessor& processor, const GrGLCaps&,
168 GrProcessorKeyBuilder* b) {
169 const CircleEffect& ce = processor.cast<CircleEffect>();
170 b->add32(ce.getEdgeType());
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())) {
182 pdman.set3f(fCircleUniform, ce.getCenter().fX, ce.getCenter().fY, radius);
183 fPrevCenter = ce.getCenter();
184 fPrevRadius = ce.getRadius();
188 //////////////////////////////////////////////////////////////////////////////
190 class GLEllipseEffect;
192 class EllipseEffect : public GrFragmentProcessor {
194 static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx,
197 virtual ~EllipseEffect() {};
198 static const char* Name() { return "Ellipse"; }
200 const SkPoint& getCenter() const { return fCenter; }
201 SkVector getRadii() const { return fRadii; }
203 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
205 typedef GLEllipseEffect GLProcessor;
207 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
210 EllipseEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry);
212 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
214 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE;
218 GrPrimitiveEdgeType fEdgeType;
220 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
222 typedef GrFragmentProcessor INHERITED;
225 GrFragmentProcessor* EllipseEffect::Create(GrPrimitiveEdgeType edgeType,
226 const SkPoint& center,
229 SkASSERT(rx >= 0 && ry >= 0);
230 return SkNEW_ARGS(EllipseEffect, (edgeType, center, rx, ry));
233 void EllipseEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
234 inout->mulByUnknownAlpha();
237 const GrBackendFragmentProcessorFactory& EllipseEffect::getFactory() const {
238 return GrTBackendFragmentProcessorFactory<EllipseEffect>::getInstance();
241 EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx, SkScalar ry)
243 , fRadii(SkVector::Make(rx, ry))
244 , fEdgeType(edgeType) {
245 this->setWillReadFragmentPosition();
248 bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
249 const EllipseEffect& ee = other.cast<EllipseEffect>();
250 return fEdgeType == ee.fEdgeType && fCenter == ee.fCenter && fRadii == ee.fRadii;
253 //////////////////////////////////////////////////////////////////////////////
255 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect);
257 GrFragmentProcessor* EllipseEffect::TestCreate(SkRandom* random,
259 const GrDrawTargetCaps& caps,
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;
268 et = (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt);
269 } while (kHairlineAA_GrProcessorEdgeType == et);
270 return EllipseEffect::Create(et, center, rx, ry);
273 //////////////////////////////////////////////////////////////////////////////
275 class GLEllipseEffect : public GrGLFragmentProcessor {
277 GLEllipseEffect(const GrBackendProcessorFactory&, const GrProcessor&);
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;
287 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
289 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
292 GrGLProgramDataManager::UniformHandle fEllipseUniform;
296 typedef GrGLFragmentProcessor INHERITED;
299 GLEllipseEffect::GLEllipseEffect(const GrBackendProcessorFactory& factory,
300 const GrProcessor& effect)
301 : INHERITED (factory) {
302 fPrevRadii.fX = -1.f;
305 void 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,
320 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
321 const char* fragmentPos = fsBuilder->fragmentPosition();
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");
334 switch (ee.getEdgeType()) {
335 case kFillAA_GrProcessorEdgeType:
336 fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
338 case kInverseFillAA_GrProcessorEdgeType:
339 fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
341 case kFillBW_GrProcessorEdgeType:
342 fsBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n");
344 case kInverseFillBW_GrProcessorEdgeType:
345 fsBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 1.0 : 0.0;\n");
347 case kHairlineAA_GrProcessorEdgeType:
348 SkFAIL("Hairline not expected here.");
351 fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
352 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
355 void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrGLCaps&,
356 GrProcessorKeyBuilder* b) {
357 const EllipseEffect& ee = effect.cast<EllipseEffect>();
358 b->add32(ee.getEdgeType());
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();
372 //////////////////////////////////////////////////////////////////////////////
374 GrFragmentProcessor* GrOvalEffect::Create(GrPrimitiveEdgeType edgeType, const SkRect& oval) {
375 if (kHairlineAA_GrProcessorEdgeType == edgeType) {
378 SkScalar w = oval.width();
379 SkScalar h = oval.height();
380 if (SkScalarNearlyEqual(w, h)) {
382 return CircleEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), w);
386 return EllipseEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), w, h);