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