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