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 "GrInvariantOutput.h" 12 #include "SkRect.h" 13 #include "glsl/GrGLSLFragmentProcessor.h" 14 #include "glsl/GrGLSLFragmentShaderBuilder.h" 15 #include "glsl/GrGLSLProgramDataManager.h" 16 #include "glsl/GrGLSLUniformHandler.h" 17 18 ////////////////////////////////////////////////////////////////////////////// 19 20 class CircleEffect : public GrFragmentProcessor { 21 public: 22 static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius); 23 24 virtual ~CircleEffect() {}; 25 26 const char* name() const override { 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 private: 34 CircleEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar radius); 35 36 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 37 38 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; 39 40 bool onIsEqual(const GrFragmentProcessor&) const override; 41 42 void onComputeInvariantOutput(GrInvariantOutput* inout) 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 GrFragmentProcessor* CircleEffect::Create(GrPrimitiveEdgeType edgeType, const SkPoint& center, 54 SkScalar radius) { 55 SkASSERT(radius >= 0); 56 return new CircleEffect(edgeType, center, radius); 57 } 58 59 void CircleEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { 60 inout->mulByUnknownSingleComponent(); 61 } 62 63 CircleEffect::CircleEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar r) 64 : fCenter(c) 65 , fRadius(r) 66 , fEdgeType(edgeType) { 67 this->initClassID<CircleEffect>(); 68 this->setWillReadFragmentPosition(); 69 } 70 71 bool CircleEffect::onIsEqual(const GrFragmentProcessor& other) const { 72 const CircleEffect& ce = other.cast<CircleEffect>(); 73 return fEdgeType == ce.fEdgeType && fCenter == ce.fCenter && fRadius == ce.fRadius; 74 } 75 76 ////////////////////////////////////////////////////////////////////////////// 77 78 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleEffect); 79 80 const GrFragmentProcessor* CircleEffect::TestCreate(GrProcessorTestData* d) { 81 SkPoint center; 82 center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f); 83 center.fY = d->fRandom->nextRangeScalar(0.f, 1000.f); 84 SkScalar radius = d->fRandom->nextRangeF(0.f, 1000.f); 85 GrPrimitiveEdgeType et; 86 do { 87 et = (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt); 88 } while (kHairlineAA_GrProcessorEdgeType == et); 89 return CircleEffect::Create(et, center, radius); 90 } 91 92 ////////////////////////////////////////////////////////////////////////////// 93 94 class GLCircleEffect : public GrGLSLFragmentProcessor { 95 public: 96 GLCircleEffect() : fPrevRadius(-1.0f) { } 97 98 virtual void emitCode(EmitArgs&) override; 99 100 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); 101 102 protected: 103 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; 104 105 private: 106 GrGLSLProgramDataManager::UniformHandle fCircleUniform; 107 SkPoint fPrevCenter; 108 SkScalar fPrevRadius; 109 110 typedef GrGLSLFragmentProcessor INHERITED; 111 }; 112 113 void GLCircleEffect::emitCode(EmitArgs& args) { 114 const CircleEffect& ce = args.fFp.cast<CircleEffect>(); 115 const char *circleName; 116 // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular 117 // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills. 118 fCircleUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, 119 kVec4f_GrSLType, kDefault_GrSLPrecision, 120 "circle", 121 &circleName); 122 123 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 124 const char* fragmentPos = fragBuilder->fragmentPosition(); 125 126 SkASSERT(kHairlineAA_GrProcessorEdgeType != ce.getEdgeType()); 127 // TODO: Right now the distance to circle caclulation is performed in a space normalized to the 128 // radius and then denormalized. This is to prevent overflow on devices that have a "real" 129 // mediump. It'd be nice to only to this on mediump devices but we currently don't have the 130 // caps here. 131 if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) { 132 fragBuilder->codeAppendf("float d = (length((%s.xy - %s.xy) * %s.w) - 1.0) * %s.z;", 133 circleName, fragmentPos, circleName, circleName); 134 } else { 135 fragBuilder->codeAppendf("float d = (1.0 - length((%s.xy - %s.xy) * %s.w)) * %s.z;", 136 circleName, fragmentPos, circleName, circleName); 137 } 138 if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) { 139 fragBuilder->codeAppend("d = clamp(d, 0.0, 1.0);"); 140 } else { 141 fragBuilder->codeAppend("d = d > 0.5 ? 1.0 : 0.0;"); 142 } 143 144 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, 145 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("d")).c_str()); 146 } 147 148 void GLCircleEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&, 149 GrProcessorKeyBuilder* b) { 150 const CircleEffect& ce = processor.cast<CircleEffect>(); 151 b->add32(ce.getEdgeType()); 152 } 153 154 void GLCircleEffect::onSetData(const GrGLSLProgramDataManager& pdman, 155 const GrProcessor& processor) { 156 const CircleEffect& ce = processor.cast<CircleEffect>(); 157 if (ce.getRadius() != fPrevRadius || ce.getCenter() != fPrevCenter) { 158 SkScalar radius = ce.getRadius(); 159 if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) { 160 radius -= 0.5f; 161 } else { 162 radius += 0.5f; 163 } 164 pdman.set4f(fCircleUniform, ce.getCenter().fX, ce.getCenter().fY, radius, 165 SkScalarInvert(radius)); 166 fPrevCenter = ce.getCenter(); 167 fPrevRadius = ce.getRadius(); 168 } 169 } 170 171 /////////////////////////////////////////////////////////////////////////////////////////////////// 172 173 void CircleEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, 174 GrProcessorKeyBuilder* b) const { 175 GLCircleEffect::GenKey(*this, caps, b); 176 } 177 178 GrGLSLFragmentProcessor* CircleEffect::onCreateGLSLInstance() const { 179 return new GLCircleEffect; 180 } 181 182 ////////////////////////////////////////////////////////////////////////////// 183 184 class EllipseEffect : public GrFragmentProcessor { 185 public: 186 static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, 187 SkScalar ry); 188 189 virtual ~EllipseEffect() {}; 190 191 const char* name() const override { return "Ellipse"; } 192 193 const SkPoint& getCenter() const { return fCenter; } 194 SkVector getRadii() const { return fRadii; } 195 196 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } 197 198 private: 199 EllipseEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry); 200 201 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 202 203 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; 204 205 bool onIsEqual(const GrFragmentProcessor&) const override; 206 207 void onComputeInvariantOutput(GrInvariantOutput* inout) const override; 208 209 SkPoint fCenter; 210 SkVector fRadii; 211 GrPrimitiveEdgeType fEdgeType; 212 213 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 214 215 typedef GrFragmentProcessor INHERITED; 216 }; 217 218 GrFragmentProcessor* EllipseEffect::Create(GrPrimitiveEdgeType edgeType, 219 const SkPoint& center, 220 SkScalar rx, 221 SkScalar ry) { 222 SkASSERT(rx >= 0 && ry >= 0); 223 return new EllipseEffect(edgeType, center, rx, ry); 224 } 225 226 void EllipseEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { 227 inout->mulByUnknownSingleComponent(); 228 } 229 230 EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx, SkScalar ry) 231 : fCenter(c) 232 , fRadii(SkVector::Make(rx, ry)) 233 , fEdgeType(edgeType) { 234 this->initClassID<EllipseEffect>(); 235 this->setWillReadFragmentPosition(); 236 } 237 238 bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const { 239 const EllipseEffect& ee = other.cast<EllipseEffect>(); 240 return fEdgeType == ee.fEdgeType && fCenter == ee.fCenter && fRadii == ee.fRadii; 241 } 242 243 ////////////////////////////////////////////////////////////////////////////// 244 245 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect); 246 247 const GrFragmentProcessor* EllipseEffect::TestCreate(GrProcessorTestData* d) { 248 SkPoint center; 249 center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f); 250 center.fY = d->fRandom->nextRangeScalar(0.f, 1000.f); 251 SkScalar rx = d->fRandom->nextRangeF(0.f, 1000.f); 252 SkScalar ry = d->fRandom->nextRangeF(0.f, 1000.f); 253 GrPrimitiveEdgeType et; 254 do { 255 et = (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt); 256 } while (kHairlineAA_GrProcessorEdgeType == et); 257 return EllipseEffect::Create(et, center, rx, ry); 258 } 259 260 ////////////////////////////////////////////////////////////////////////////// 261 262 class GLEllipseEffect : public GrGLSLFragmentProcessor { 263 public: 264 GLEllipseEffect() { 265 fPrevRadii.fX = -1.0f; 266 } 267 268 void emitCode(EmitArgs&) override; 269 270 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*); 271 272 protected: 273 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; 274 275 private: 276 GrGLSLProgramDataManager::UniformHandle fEllipseUniform; 277 GrGLSLProgramDataManager::UniformHandle fScaleUniform; 278 SkPoint fPrevCenter; 279 SkVector fPrevRadii; 280 281 typedef GrGLSLFragmentProcessor INHERITED; 282 }; 283 284 void GLEllipseEffect::emitCode(EmitArgs& args) { 285 const EllipseEffect& ee = args.fFp.cast<EllipseEffect>(); 286 const char *ellipseName; 287 // The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2) 288 // The last two terms can underflow on mediump, so we use highp. 289 fEllipseUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, 290 kVec4f_GrSLType, kHigh_GrSLPrecision, 291 "ellipse", 292 &ellipseName); 293 // If we're on a device with a "real" mediump then we'll do the distance computation in a space 294 // that is normalized by the larger radius. The scale uniform will be scale, 1/scale. The 295 // inverse squared radii uniform values are already in this normalized space. The center is 296 // not. 297 const char* scaleName = nullptr; 298 if (args.fGLSLCaps->floatPrecisionVaries()) { 299 fScaleUniform = args.fUniformHandler->addUniform( 300 kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, 301 "scale", &scaleName); 302 } 303 304 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 305 const char* fragmentPos = fragBuilder->fragmentPosition(); 306 307 // d is the offset to the ellipse center 308 fragBuilder->codeAppendf("vec2 d = %s.xy - %s.xy;", fragmentPos, ellipseName); 309 if (scaleName) { 310 fragBuilder->codeAppendf("d *= %s.y;", scaleName); 311 } 312 fragBuilder->codeAppendf("vec2 Z = d * %s.zw;", ellipseName); 313 // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1. 314 fragBuilder->codeAppend("float implicit = dot(Z, d) - 1.0;"); 315 // grad_dot is the squared length of the gradient of the implicit. 316 fragBuilder->codeAppendf("float grad_dot = 4.0 * dot(Z, Z);"); 317 // Avoid calling inversesqrt on zero. 318 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);"); 319 fragBuilder->codeAppendf("float approx_dist = implicit * inversesqrt(grad_dot);"); 320 if (scaleName) { 321 fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName); 322 } 323 324 switch (ee.getEdgeType()) { 325 case kFillAA_GrProcessorEdgeType: 326 fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);"); 327 break; 328 case kInverseFillAA_GrProcessorEdgeType: 329 fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); 330 break; 331 case kFillBW_GrProcessorEdgeType: 332 fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 0.0 : 1.0;"); 333 break; 334 case kInverseFillBW_GrProcessorEdgeType: 335 fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 1.0 : 0.0;"); 336 break; 337 case kHairlineAA_GrProcessorEdgeType: 338 SkFAIL("Hairline not expected here."); 339 } 340 341 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, 342 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); 343 } 344 345 void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrGLSLCaps&, 346 GrProcessorKeyBuilder* b) { 347 const EllipseEffect& ee = effect.cast<EllipseEffect>(); 348 b->add32(ee.getEdgeType()); 349 } 350 351 void GLEllipseEffect::onSetData(const GrGLSLProgramDataManager& pdman, 352 const GrProcessor& effect) { 353 const EllipseEffect& ee = effect.cast<EllipseEffect>(); 354 if (ee.getRadii() != fPrevRadii || ee.getCenter() != fPrevCenter) { 355 float invRXSqd; 356 float invRYSqd; 357 // If we're using a scale factor to work around precision issues, choose the larger radius 358 // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. 359 if (fScaleUniform.isValid()) { 360 if (ee.getRadii().fX > ee.getRadii().fY) { 361 invRXSqd = 1.f; 362 invRYSqd = (ee.getRadii().fX * ee.getRadii().fX) / 363 (ee.getRadii().fY * ee.getRadii().fY); 364 pdman.set2f(fScaleUniform, ee.getRadii().fX, 1.f / ee.getRadii().fX); 365 } else { 366 invRXSqd = (ee.getRadii().fY * ee.getRadii().fY) / 367 (ee.getRadii().fX * ee.getRadii().fX); 368 invRYSqd = 1.f; 369 pdman.set2f(fScaleUniform, ee.getRadii().fY, 1.f / ee.getRadii().fY); 370 } 371 } else { 372 invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX); 373 invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY); 374 } 375 pdman.set4f(fEllipseUniform, ee.getCenter().fX, ee.getCenter().fY, invRXSqd, invRYSqd); 376 fPrevCenter = ee.getCenter(); 377 fPrevRadii = ee.getRadii(); 378 } 379 } 380 381 /////////////////////////////////////////////////////////////////////////////////////////////////// 382 383 void EllipseEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, 384 GrProcessorKeyBuilder* b) const { 385 GLEllipseEffect::GenKey(*this, caps, b); 386 } 387 388 GrGLSLFragmentProcessor* EllipseEffect::onCreateGLSLInstance() const { 389 return new GLEllipseEffect; 390 } 391 392 ////////////////////////////////////////////////////////////////////////////// 393 394 GrFragmentProcessor* GrOvalEffect::Create(GrPrimitiveEdgeType edgeType, const SkRect& oval) { 395 if (kHairlineAA_GrProcessorEdgeType == edgeType) { 396 return nullptr; 397 } 398 SkScalar w = oval.width(); 399 SkScalar h = oval.height(); 400 if (SkScalarNearlyEqual(w, h)) { 401 w /= 2; 402 return CircleEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), w); 403 } else { 404 w /= 2; 405 h /= 2; 406 return EllipseEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), w, h); 407 } 408 409 return nullptr; 410 } 411