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 21class CircleEffect : public GrFragmentProcessor { 22public: 23 static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, const SkPoint& center, 24 SkScalar radius); 25 26 ~CircleEffect() override {} 27 28 const char* name() const override { return "Circle"; } 29 30 const SkPoint& getCenter() const { return fCenter; } 31 SkScalar getRadius() const { return fRadius; } 32 33 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } 34 35private: 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 53sk_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 59CircleEffect::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 67bool 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 74GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleEffect); 75 76#if GR_TEST_UTILS 77sk_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 92class GLCircleEffect : public GrGLSLFragmentProcessor { 93public: 94 GLCircleEffect() : fPrevRadius(-1.0f) { } 95 96 virtual void emitCode(EmitArgs&) override; 97 98 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); 99 100protected: 101 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; 102 103private: 104 GrGLSLProgramDataManager::UniformHandle fCircleUniform; 105 SkPoint fPrevCenter; 106 SkScalar fPrevRadius; 107 108 typedef GrGLSLFragmentProcessor INHERITED; 109}; 110 111void 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 147void GLCircleEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, 148 GrProcessorKeyBuilder* b) { 149 const CircleEffect& ce = processor.cast<CircleEffect>(); 150 b->add32(ce.getEdgeType()); 151} 152 153void 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 172void CircleEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, 173 GrProcessorKeyBuilder* b) const { 174 GLCircleEffect::GenKey(*this, caps, b); 175} 176 177GrGLSLFragmentProcessor* CircleEffect::onCreateGLSLInstance() const { 178 return new GLCircleEffect; 179} 180 181////////////////////////////////////////////////////////////////////////////// 182 183class EllipseEffect : public GrFragmentProcessor { 184public: 185 static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, const SkPoint& center, 186 SkScalar rx, SkScalar ry); 187 188 ~EllipseEffect() override {} 189 190 const char* name() const override { return "Ellipse"; } 191 192 const SkPoint& getCenter() const { return fCenter; } 193 SkVector getRadii() const { return fRadii; } 194 195 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } 196 197private: 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 215sk_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 223EllipseEffect::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 232bool 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 239GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect); 240 241#if GR_TEST_UTILS 242sk_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 258class GLEllipseEffect : public GrGLSLFragmentProcessor { 259public: 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 268protected: 269 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; 270 271private: 272 GrGLSLProgramDataManager::UniformHandle fEllipseUniform; 273 GrGLSLProgramDataManager::UniformHandle fScaleUniform; 274 SkPoint fPrevCenter; 275 SkVector fPrevRadii; 276 277 typedef GrGLSLFragmentProcessor INHERITED; 278}; 279 280void 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 340void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&, 341 GrProcessorKeyBuilder* b) { 342 const EllipseEffect& ee = effect.cast<EllipseEffect>(); 343 b->add32(ee.getEdgeType()); 344} 345 346void 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 378void EllipseEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, 379 GrProcessorKeyBuilder* b) const { 380 GLEllipseEffect::GenKey(*this, caps, b); 381} 382 383GrGLSLFragmentProcessor* EllipseEffect::onCreateGLSLInstance() const { 384 return new GLEllipseEffect; 385} 386 387////////////////////////////////////////////////////////////////////////////// 388 389sk_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