1 /* 2 * Copyright 2013 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 "GrOvalRenderer.h" 9 10 #include "gl/builders/GrGLFullProgramBuilder.h" 11 #include "gl/GrGLProcessor.h" 12 #include "gl/GrGLSL.h" 13 #include "gl/GrGLGeometryProcessor.h" 14 #include "GrProcessor.h" 15 #include "GrTBackendProcessorFactory.h" 16 17 #include "GrDrawState.h" 18 #include "GrDrawTarget.h" 19 #include "GrGpu.h" 20 21 #include "SkRRect.h" 22 #include "SkStrokeRec.h" 23 #include "SkTLazy.h" 24 25 #include "GrGeometryProcessor.h" 26 #include "effects/GrRRectEffect.h" 27 28 namespace { 29 30 struct CircleVertex { 31 SkPoint fPos; 32 SkPoint fOffset; 33 SkScalar fOuterRadius; 34 SkScalar fInnerRadius; 35 }; 36 37 struct EllipseVertex { 38 SkPoint fPos; 39 SkPoint fOffset; 40 SkPoint fOuterRadii; 41 SkPoint fInnerRadii; 42 }; 43 44 struct DIEllipseVertex { 45 SkPoint fPos; 46 SkPoint fOuterOffset; 47 SkPoint fInnerOffset; 48 }; 49 50 inline bool circle_stays_circle(const SkMatrix& m) { 51 return m.isSimilarity(); 52 } 53 54 } 55 56 /////////////////////////////////////////////////////////////////////////////// 57 58 /** 59 * The output of this effect is a modulation of the input color and coverage for a circle, 60 * specified as offset_x, offset_y (both from center point), outer radius and inner radius. 61 */ 62 63 class CircleEdgeEffect : public GrGeometryProcessor { 64 public: 65 static GrGeometryProcessor* Create(bool stroke) { 66 GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gCircleStrokeEdge, CircleEdgeEffect, (true)); 67 GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gCircleFillEdge, CircleEdgeEffect, (false)); 68 69 if (stroke) { 70 gCircleStrokeEdge->ref(); 71 return gCircleStrokeEdge; 72 } else { 73 gCircleFillEdge->ref(); 74 return gCircleFillEdge; 75 } 76 } 77 78 virtual void getConstantColorComponents(GrColor* color, 79 uint32_t* validFlags) const SK_OVERRIDE { 80 *validFlags = 0; 81 } 82 83 const GrShaderVar& inCircleEdge() const { return fInCircleEdge; } 84 85 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE { 86 return GrTBackendGeometryProcessorFactory<CircleEdgeEffect>::getInstance(); 87 } 88 89 virtual ~CircleEdgeEffect() {} 90 91 static const char* Name() { return "CircleEdge"; } 92 93 inline bool isStroked() const { return fStroke; } 94 95 class GLProcessor : public GrGLGeometryProcessor { 96 public: 97 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&) 98 : INHERITED (factory) {} 99 100 virtual void emitCode(GrGLFullProgramBuilder* builder, 101 const GrGeometryProcessor& geometryProcessor, 102 const GrProcessorKey& key, 103 const char* outputColor, 104 const char* inputColor, 105 const TransformedCoordsArray&, 106 const TextureSamplerArray& samplers) SK_OVERRIDE { 107 const CircleEdgeEffect& circleEffect = geometryProcessor.cast<CircleEdgeEffect>(); 108 const char *vsName, *fsName; 109 builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName); 110 111 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();; 112 vsBuilder->codeAppendf("\t%s = %s;\n", vsName, circleEffect.inCircleEdge().c_str()); 113 114 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 115 fsBuilder->codeAppendf("\tfloat d = length(%s.xy);\n", fsName); 116 fsBuilder->codeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName); 117 if (circleEffect.isStroked()) { 118 fsBuilder->codeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName); 119 fsBuilder->codeAppend("\tedgeAlpha *= innerAlpha;\n"); 120 } 121 122 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor, 123 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str()); 124 } 125 126 static void GenKey(const GrProcessor& processor, const GrGLCaps&, 127 GrProcessorKeyBuilder* b) { 128 const CircleEdgeEffect& circleEffect = processor.cast<CircleEdgeEffect>(); 129 b->add32(circleEffect.isStroked()); 130 } 131 132 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {} 133 134 private: 135 typedef GrGLGeometryProcessor INHERITED; 136 }; 137 138 139 private: 140 CircleEdgeEffect(bool stroke) 141 : fInCircleEdge(this->addVertexAttrib( 142 GrShaderVar("inCircleEdge", 143 kVec4f_GrSLType, 144 GrShaderVar::kAttribute_TypeModifier))) { 145 fStroke = stroke; 146 } 147 148 virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE { 149 const CircleEdgeEffect& cee = other.cast<CircleEdgeEffect>(); 150 return cee.fStroke == fStroke; 151 } 152 153 const GrShaderVar& fInCircleEdge; 154 bool fStroke; 155 156 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; 157 158 typedef GrGeometryProcessor INHERITED; 159 }; 160 161 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleEdgeEffect); 162 163 GrGeometryProcessor* CircleEdgeEffect::TestCreate(SkRandom* random, 164 GrContext* context, 165 const GrDrawTargetCaps&, 166 GrTexture* textures[]) { 167 return CircleEdgeEffect::Create(random->nextBool()); 168 } 169 170 /////////////////////////////////////////////////////////////////////////////// 171 172 /** 173 * The output of this effect is a modulation of the input color and coverage for an axis-aligned 174 * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii, 175 * in both x and y directions. 176 * 177 * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0. 178 */ 179 180 class EllipseEdgeEffect : public GrGeometryProcessor { 181 public: 182 static GrGeometryProcessor* Create(bool stroke) { 183 GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseStrokeEdge, EllipseEdgeEffect, (true)); 184 GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseFillEdge, EllipseEdgeEffect, (false)); 185 186 if (stroke) { 187 gEllipseStrokeEdge->ref(); 188 return gEllipseStrokeEdge; 189 } else { 190 gEllipseFillEdge->ref(); 191 return gEllipseFillEdge; 192 } 193 } 194 195 virtual void getConstantColorComponents(GrColor* color, 196 uint32_t* validFlags) const SK_OVERRIDE { 197 *validFlags = 0; 198 } 199 200 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE { 201 return GrTBackendGeometryProcessorFactory<EllipseEdgeEffect>::getInstance(); 202 } 203 204 virtual ~EllipseEdgeEffect() {} 205 206 static const char* Name() { return "EllipseEdge"; } 207 208 const GrShaderVar& inEllipseOffset() const { return fInEllipseOffset; } 209 const GrShaderVar& inEllipseRadii() const { return fInEllipseRadii; } 210 211 inline bool isStroked() const { return fStroke; } 212 213 class GLProcessor : public GrGLGeometryProcessor { 214 public: 215 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&) 216 : INHERITED (factory) {} 217 218 virtual void emitCode(GrGLFullProgramBuilder* builder, 219 const GrGeometryProcessor& geometryProcessor, 220 const GrProcessorKey& key, 221 const char* outputColor, 222 const char* inputColor, 223 const TransformedCoordsArray&, 224 const TextureSamplerArray& samplers) SK_OVERRIDE { 225 const EllipseEdgeEffect& ellipseEffect = geometryProcessor.cast<EllipseEdgeEffect>(); 226 227 const char *vsOffsetName, *fsOffsetName; 228 const char *vsRadiiName, *fsRadiiName; 229 230 builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName, &fsOffsetName); 231 232 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder(); 233 vsBuilder->codeAppendf("%s = %s;", vsOffsetName, 234 ellipseEffect.inEllipseOffset().c_str()); 235 236 builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName); 237 vsBuilder->codeAppendf("%s = %s;", vsRadiiName, ellipseEffect.inEllipseRadii().c_str()); 238 239 // for outer curve 240 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 241 fsBuilder->codeAppendf("\tvec2 scaledOffset = %s*%s.xy;\n", fsOffsetName, fsRadiiName); 242 fsBuilder->codeAppend("\tfloat test = dot(scaledOffset, scaledOffset) - 1.0;\n"); 243 fsBuilder->codeAppendf("\tvec2 grad = 2.0*scaledOffset*%s.xy;\n", fsRadiiName); 244 fsBuilder->codeAppend("\tfloat grad_dot = dot(grad, grad);\n"); 245 // avoid calling inversesqrt on zero. 246 fsBuilder->codeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n"); 247 fsBuilder->codeAppend("\tfloat invlen = inversesqrt(grad_dot);\n"); 248 fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n"); 249 250 // for inner curve 251 if (ellipseEffect.isStroked()) { 252 fsBuilder->codeAppendf("\tscaledOffset = %s*%s.zw;\n", fsOffsetName, fsRadiiName); 253 fsBuilder->codeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n"); 254 fsBuilder->codeAppendf("\tgrad = 2.0*scaledOffset*%s.zw;\n", fsRadiiName); 255 fsBuilder->codeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n"); 256 fsBuilder->codeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n"); 257 } 258 259 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor, 260 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str()); 261 } 262 263 static void GenKey(const GrProcessor& processor, const GrGLCaps&, 264 GrProcessorKeyBuilder* b) { 265 const EllipseEdgeEffect& ellipseEffect = processor.cast<EllipseEdgeEffect>(); 266 b->add32(ellipseEffect.isStroked()); 267 } 268 269 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE { 270 } 271 272 private: 273 typedef GrGLGeometryProcessor INHERITED; 274 }; 275 276 private: 277 EllipseEdgeEffect(bool stroke) 278 : fInEllipseOffset(this->addVertexAttrib( 279 GrShaderVar("inEllipseOffset", 280 kVec2f_GrSLType, 281 GrShaderVar::kAttribute_TypeModifier))) 282 , fInEllipseRadii(this->addVertexAttrib( 283 GrShaderVar("inEllipseRadii", 284 kVec4f_GrSLType, 285 GrShaderVar::kAttribute_TypeModifier))) { 286 fStroke = stroke; 287 } 288 289 virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE { 290 const EllipseEdgeEffect& eee = other.cast<EllipseEdgeEffect>(); 291 return eee.fStroke == fStroke; 292 } 293 294 const GrShaderVar& fInEllipseOffset; 295 const GrShaderVar& fInEllipseRadii; 296 bool fStroke; 297 298 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; 299 300 typedef GrGeometryProcessor INHERITED; 301 }; 302 303 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseEdgeEffect); 304 305 GrGeometryProcessor* EllipseEdgeEffect::TestCreate(SkRandom* random, 306 GrContext* context, 307 const GrDrawTargetCaps&, 308 GrTexture* textures[]) { 309 return EllipseEdgeEffect::Create(random->nextBool()); 310 } 311 312 /////////////////////////////////////////////////////////////////////////////// 313 314 /** 315 * The output of this effect is a modulation of the input color and coverage for an ellipse, 316 * specified as a 2D offset from center for both the outer and inner paths (if stroked). The 317 * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge corrected by 318 * using differentials. 319 * 320 * The result is device-independent and can be used with any affine matrix. 321 */ 322 323 class DIEllipseEdgeEffect : public GrGeometryProcessor { 324 public: 325 enum Mode { kStroke = 0, kHairline, kFill }; 326 327 static GrGeometryProcessor* Create(Mode mode) { 328 GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseStrokeEdge, DIEllipseEdgeEffect, (kStroke)); 329 GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseHairlineEdge, DIEllipseEdgeEffect, (kHairline)); 330 GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseFillEdge, DIEllipseEdgeEffect, (kFill)); 331 332 if (kStroke == mode) { 333 gEllipseStrokeEdge->ref(); 334 return gEllipseStrokeEdge; 335 } else if (kHairline == mode) { 336 gEllipseHairlineEdge->ref(); 337 return gEllipseHairlineEdge; 338 } else { 339 gEllipseFillEdge->ref(); 340 return gEllipseFillEdge; 341 } 342 } 343 344 virtual void getConstantColorComponents(GrColor* color, 345 uint32_t* validFlags) const SK_OVERRIDE { 346 *validFlags = 0; 347 } 348 349 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE { 350 return GrTBackendGeometryProcessorFactory<DIEllipseEdgeEffect>::getInstance(); 351 } 352 353 virtual ~DIEllipseEdgeEffect() {} 354 355 static const char* Name() { return "DIEllipseEdge"; } 356 357 const GrShaderVar& inEllipseOffsets0() const { return fInEllipseOffsets0; } 358 const GrShaderVar& inEllipseOffsets1() const { return fInEllipseOffsets1; } 359 360 inline Mode getMode() const { return fMode; } 361 362 class GLProcessor : public GrGLGeometryProcessor { 363 public: 364 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&) 365 : INHERITED (factory) {} 366 367 virtual void emitCode(GrGLFullProgramBuilder* builder, 368 const GrGeometryProcessor& geometryProcessor, 369 const GrProcessorKey& key, 370 const char* outputColor, 371 const char* inputColor, 372 const TransformedCoordsArray&, 373 const TextureSamplerArray& samplers) SK_OVERRIDE { 374 const DIEllipseEdgeEffect& ellipseEffect = 375 geometryProcessor.cast<DIEllipseEdgeEffect>(); 376 377 const char *vsOffsetName0, *fsOffsetName0; 378 builder->addVarying(kVec2f_GrSLType, "EllipseOffsets0", 379 &vsOffsetName0, &fsOffsetName0); 380 381 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder(); 382 vsBuilder->codeAppendf("%s = %s;", vsOffsetName0, 383 ellipseEffect.inEllipseOffsets0().c_str()); 384 const char *vsOffsetName1, *fsOffsetName1; 385 builder->addVarying(kVec2f_GrSLType, "EllipseOffsets1", 386 &vsOffsetName1, &fsOffsetName1); 387 vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName1, 388 ellipseEffect.inEllipseOffsets1().c_str()); 389 390 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 391 SkAssertResult(fsBuilder->enableFeature( 392 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); 393 // for outer curve 394 fsBuilder->codeAppendf("\tvec2 scaledOffset = %s.xy;\n", fsOffsetName0); 395 fsBuilder->codeAppend("\tfloat test = dot(scaledOffset, scaledOffset) - 1.0;\n"); 396 fsBuilder->codeAppendf("\tvec2 duvdx = dFdx(%s);\n", fsOffsetName0); 397 fsBuilder->codeAppendf("\tvec2 duvdy = dFdy(%s);\n", fsOffsetName0); 398 fsBuilder->codeAppendf("\tvec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,\n" 399 "\t 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);\n", 400 fsOffsetName0, fsOffsetName0, fsOffsetName0, fsOffsetName0); 401 402 fsBuilder->codeAppend("\tfloat grad_dot = dot(grad, grad);\n"); 403 // avoid calling inversesqrt on zero. 404 fsBuilder->codeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n"); 405 fsBuilder->codeAppend("\tfloat invlen = inversesqrt(grad_dot);\n"); 406 if (kHairline == ellipseEffect.getMode()) { 407 // can probably do this with one step 408 fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);\n"); 409 fsBuilder->codeAppend("\tedgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);\n"); 410 } else { 411 fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n"); 412 } 413 414 // for inner curve 415 if (kStroke == ellipseEffect.getMode()) { 416 fsBuilder->codeAppendf("\tscaledOffset = %s.xy;\n", fsOffsetName1); 417 fsBuilder->codeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n"); 418 fsBuilder->codeAppendf("\tduvdx = dFdx(%s);\n", fsOffsetName1); 419 fsBuilder->codeAppendf("\tduvdy = dFdy(%s);\n", fsOffsetName1); 420 fsBuilder->codeAppendf("\tgrad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,\n" 421 "\t 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);\n", 422 fsOffsetName1, fsOffsetName1, fsOffsetName1, fsOffsetName1); 423 fsBuilder->codeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n"); 424 fsBuilder->codeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n"); 425 } 426 427 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor, 428 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str()); 429 } 430 431 static void GenKey(const GrProcessor& processor, const GrGLCaps&, 432 GrProcessorKeyBuilder* b) { 433 const DIEllipseEdgeEffect& ellipseEffect = processor.cast<DIEllipseEdgeEffect>(); 434 435 b->add32(ellipseEffect.getMode()); 436 } 437 438 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE { 439 } 440 441 private: 442 typedef GrGLGeometryProcessor INHERITED; 443 }; 444 445 private: 446 DIEllipseEdgeEffect(Mode mode) 447 : fInEllipseOffsets0(this->addVertexAttrib( 448 GrShaderVar("inEllipseOffsets0", 449 kVec2f_GrSLType, 450 GrShaderVar::kAttribute_TypeModifier))) 451 , fInEllipseOffsets1(this->addVertexAttrib( 452 GrShaderVar("inEllipseOffsets1", 453 kVec2f_GrSLType, 454 GrShaderVar::kAttribute_TypeModifier))) { 455 fMode = mode; 456 } 457 458 virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE { 459 const DIEllipseEdgeEffect& eee = other.cast<DIEllipseEdgeEffect>(); 460 return eee.fMode == fMode; 461 } 462 463 const GrShaderVar& fInEllipseOffsets0; 464 const GrShaderVar& fInEllipseOffsets1; 465 Mode fMode; 466 467 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; 468 469 typedef GrGeometryProcessor INHERITED; 470 }; 471 472 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseEdgeEffect); 473 474 GrGeometryProcessor* DIEllipseEdgeEffect::TestCreate(SkRandom* random, 475 GrContext* context, 476 const GrDrawTargetCaps&, 477 GrTexture* textures[]) { 478 return DIEllipseEdgeEffect::Create((Mode)(random->nextRangeU(0,2))); 479 } 480 481 /////////////////////////////////////////////////////////////////////////////// 482 483 void GrOvalRenderer::reset() { 484 SkSafeSetNull(fRRectIndexBuffer); 485 } 486 487 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, bool useAA, 488 const SkRect& oval, const SkStrokeRec& stroke) 489 { 490 bool useCoverageAA = useAA && 491 !target->getDrawState().getRenderTarget()->isMultisampled() && 492 !target->shouldDisableCoverageAAForBlend(); 493 494 if (!useCoverageAA) { 495 return false; 496 } 497 498 const SkMatrix& vm = context->getMatrix(); 499 500 // we can draw circles 501 if (SkScalarNearlyEqual(oval.width(), oval.height()) 502 && circle_stays_circle(vm)) { 503 this->drawCircle(target, useCoverageAA, oval, stroke); 504 // if we have shader derivative support, render as device-independent 505 } else if (target->caps()->shaderDerivativeSupport()) { 506 return this->drawDIEllipse(target, useCoverageAA, oval, stroke); 507 // otherwise axis-aligned ellipses only 508 } else if (vm.rectStaysRect()) { 509 return this->drawEllipse(target, useCoverageAA, oval, stroke); 510 } else { 511 return false; 512 } 513 514 return true; 515 } 516 517 /////////////////////////////////////////////////////////////////////////////// 518 519 // position + edge 520 extern const GrVertexAttrib gCircleVertexAttribs[] = { 521 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 522 {kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding} 523 }; 524 525 void GrOvalRenderer::drawCircle(GrDrawTarget* target, 526 bool useCoverageAA, 527 const SkRect& circle, 528 const SkStrokeRec& stroke) 529 { 530 GrDrawState* drawState = target->drawState(); 531 532 const SkMatrix& vm = drawState->getViewMatrix(); 533 SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY()); 534 vm.mapPoints(¢er, 1); 535 SkScalar radius = vm.mapRadius(SkScalarHalf(circle.width())); 536 SkScalar strokeWidth = vm.mapRadius(stroke.getWidth()); 537 538 GrDrawState::AutoViewMatrixRestore avmr; 539 if (!avmr.setIdentity(drawState)) { 540 return; 541 } 542 543 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircleVertexAttribs), 544 sizeof(CircleVertex)); 545 546 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); 547 if (!geo.succeeded()) { 548 GrPrintf("Failed to get space for vertices!\n"); 549 return; 550 } 551 552 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); 553 554 SkStrokeRec::Style style = stroke.getStyle(); 555 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || 556 SkStrokeRec::kHairline_Style == style; 557 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; 558 559 SkScalar innerRadius = 0.0f; 560 SkScalar outerRadius = radius; 561 SkScalar halfWidth = 0; 562 if (hasStroke) { 563 if (SkScalarNearlyZero(strokeWidth)) { 564 halfWidth = SK_ScalarHalf; 565 } else { 566 halfWidth = SkScalarHalf(strokeWidth); 567 } 568 569 outerRadius += halfWidth; 570 if (isStrokeOnly) { 571 innerRadius = radius - halfWidth; 572 } 573 } 574 575 GrGeometryProcessor* gp = CircleEdgeEffect::Create(isStrokeOnly && innerRadius > 0); 576 drawState->setGeometryProcessor(gp)->unref(); 577 578 // The radii are outset for two reasons. First, it allows the shader to simply perform 579 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the 580 // verts of the bounding box that is rendered and the outset ensures the box will cover all 581 // pixels partially covered by the circle. 582 outerRadius += SK_ScalarHalf; 583 innerRadius -= SK_ScalarHalf; 584 585 SkRect bounds = SkRect::MakeLTRB( 586 center.fX - outerRadius, 587 center.fY - outerRadius, 588 center.fX + outerRadius, 589 center.fY + outerRadius 590 ); 591 592 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); 593 verts[0].fOffset = SkPoint::Make(-outerRadius, -outerRadius); 594 verts[0].fOuterRadius = outerRadius; 595 verts[0].fInnerRadius = innerRadius; 596 597 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); 598 verts[1].fOffset = SkPoint::Make(outerRadius, -outerRadius); 599 verts[1].fOuterRadius = outerRadius; 600 verts[1].fInnerRadius = innerRadius; 601 602 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); 603 verts[2].fOffset = SkPoint::Make(-outerRadius, outerRadius); 604 verts[2].fOuterRadius = outerRadius; 605 verts[2].fInnerRadius = innerRadius; 606 607 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 608 verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius); 609 verts[3].fOuterRadius = outerRadius; 610 verts[3].fInnerRadius = innerRadius; 611 612 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); 613 } 614 615 /////////////////////////////////////////////////////////////////////////////// 616 617 // position + offset + 1/radii 618 extern const GrVertexAttrib gEllipseVertexAttribs[] = { 619 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 620 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}, 621 {kVec4f_GrVertexAttribType, 2*sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding} 622 }; 623 624 // position + offsets 625 extern const GrVertexAttrib gDIEllipseVertexAttribs[] = { 626 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 627 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}, 628 {kVec2f_GrVertexAttribType, 2*sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}, 629 }; 630 631 bool GrOvalRenderer::drawEllipse(GrDrawTarget* target, 632 bool useCoverageAA, 633 const SkRect& ellipse, 634 const SkStrokeRec& stroke) 635 { 636 GrDrawState* drawState = target->drawState(); 637 #ifdef SK_DEBUG 638 { 639 // we should have checked for this previously 640 bool isAxisAlignedEllipse = drawState->getViewMatrix().rectStaysRect(); 641 SkASSERT(useCoverageAA && isAxisAlignedEllipse); 642 } 643 #endif 644 645 // do any matrix crunching before we reset the draw state for device coords 646 const SkMatrix& vm = drawState->getViewMatrix(); 647 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY()); 648 vm.mapPoints(¢er, 1); 649 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width()); 650 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height()); 651 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*ellipseXRadius + 652 vm[SkMatrix::kMSkewY]*ellipseYRadius); 653 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius + 654 vm[SkMatrix::kMScaleY]*ellipseYRadius); 655 656 // do (potentially) anisotropic mapping of stroke 657 SkVector scaledStroke; 658 SkScalar strokeWidth = stroke.getWidth(); 659 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMatrix::kMSkewY])); 660 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatrix::kMScaleY])); 661 662 SkStrokeRec::Style style = stroke.getStyle(); 663 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || 664 SkStrokeRec::kHairline_Style == style; 665 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; 666 667 SkScalar innerXRadius = 0; 668 SkScalar innerYRadius = 0; 669 if (hasStroke) { 670 if (SkScalarNearlyZero(scaledStroke.length())) { 671 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); 672 } else { 673 scaledStroke.scale(SK_ScalarHalf); 674 } 675 676 // we only handle thick strokes for near-circular ellipses 677 if (scaledStroke.length() > SK_ScalarHalf && 678 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) { 679 return false; 680 } 681 682 // we don't handle it if curvature of the stroke is less than curvature of the ellipse 683 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius || 684 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) { 685 return false; 686 } 687 688 // this is legit only if scale & translation (which should be the case at the moment) 689 if (isStrokeOnly) { 690 innerXRadius = xRadius - scaledStroke.fX; 691 innerYRadius = yRadius - scaledStroke.fY; 692 } 693 694 xRadius += scaledStroke.fX; 695 yRadius += scaledStroke.fY; 696 } 697 698 GrDrawState::AutoViewMatrixRestore avmr; 699 if (!avmr.setIdentity(drawState)) { 700 return false; 701 } 702 703 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVertexAttribs), 704 sizeof(EllipseVertex)); 705 706 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); 707 if (!geo.succeeded()) { 708 GrPrintf("Failed to get space for vertices!\n"); 709 return false; 710 } 711 712 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); 713 714 GrGeometryProcessor* gp = EllipseEdgeEffect::Create(isStrokeOnly && 715 innerXRadius > 0 && innerYRadius > 0); 716 717 drawState->setGeometryProcessor(gp)->unref(); 718 719 // Compute the reciprocals of the radii here to save time in the shader 720 SkScalar xRadRecip = SkScalarInvert(xRadius); 721 SkScalar yRadRecip = SkScalarInvert(yRadius); 722 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius); 723 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius); 724 725 // We've extended the outer x radius out half a pixel to antialias. 726 // This will also expand the rect so all the pixels will be captured. 727 // TODO: Consider if we should use sqrt(2)/2 instead 728 xRadius += SK_ScalarHalf; 729 yRadius += SK_ScalarHalf; 730 731 SkRect bounds = SkRect::MakeLTRB( 732 center.fX - xRadius, 733 center.fY - yRadius, 734 center.fX + xRadius, 735 center.fY + yRadius 736 ); 737 738 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); 739 verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius); 740 verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 741 verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 742 743 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); 744 verts[1].fOffset = SkPoint::Make(xRadius, -yRadius); 745 verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 746 verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 747 748 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); 749 verts[2].fOffset = SkPoint::Make(-xRadius, yRadius); 750 verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 751 verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 752 753 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 754 verts[3].fOffset = SkPoint::Make(xRadius, yRadius); 755 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 756 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 757 758 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); 759 760 return true; 761 } 762 763 bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target, 764 bool useCoverageAA, 765 const SkRect& ellipse, 766 const SkStrokeRec& stroke) 767 { 768 GrDrawState* drawState = target->drawState(); 769 const SkMatrix& vm = drawState->getViewMatrix(); 770 771 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY()); 772 SkScalar xRadius = SkScalarHalf(ellipse.width()); 773 SkScalar yRadius = SkScalarHalf(ellipse.height()); 774 775 SkStrokeRec::Style style = stroke.getStyle(); 776 DIEllipseEdgeEffect::Mode mode = (SkStrokeRec::kStroke_Style == style) ? 777 DIEllipseEdgeEffect::kStroke : 778 (SkStrokeRec::kHairline_Style == style) ? 779 DIEllipseEdgeEffect::kHairline : DIEllipseEdgeEffect::kFill; 780 781 SkScalar innerXRadius = 0; 782 SkScalar innerYRadius = 0; 783 if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) { 784 SkScalar strokeWidth = stroke.getWidth(); 785 786 if (SkScalarNearlyZero(strokeWidth)) { 787 strokeWidth = SK_ScalarHalf; 788 } else { 789 strokeWidth *= SK_ScalarHalf; 790 } 791 792 // we only handle thick strokes for near-circular ellipses 793 if (strokeWidth > SK_ScalarHalf && 794 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) { 795 return false; 796 } 797 798 // we don't handle it if curvature of the stroke is less than curvature of the ellipse 799 if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius || 800 strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) { 801 return false; 802 } 803 804 // set inner radius (if needed) 805 if (SkStrokeRec::kStroke_Style == style) { 806 innerXRadius = xRadius - strokeWidth; 807 innerYRadius = yRadius - strokeWidth; 808 } 809 810 xRadius += strokeWidth; 811 yRadius += strokeWidth; 812 } 813 if (DIEllipseEdgeEffect::kStroke == mode) { 814 mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kStroke : 815 DIEllipseEdgeEffect::kFill; 816 } 817 SkScalar innerRatioX = SkScalarDiv(xRadius, innerXRadius); 818 SkScalar innerRatioY = SkScalarDiv(yRadius, innerYRadius); 819 820 drawState->setVertexAttribs<gDIEllipseVertexAttribs>(SK_ARRAY_COUNT(gDIEllipseVertexAttribs), 821 sizeof(DIEllipseVertex)); 822 823 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); 824 if (!geo.succeeded()) { 825 GrPrintf("Failed to get space for vertices!\n"); 826 return false; 827 } 828 829 DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(geo.vertices()); 830 831 GrGeometryProcessor* gp = DIEllipseEdgeEffect::Create(mode); 832 833 drawState->setGeometryProcessor(gp)->unref(); 834 835 // This expands the outer rect so that after CTM we end up with a half-pixel border 836 SkScalar a = vm[SkMatrix::kMScaleX]; 837 SkScalar b = vm[SkMatrix::kMSkewX]; 838 SkScalar c = vm[SkMatrix::kMSkewY]; 839 SkScalar d = vm[SkMatrix::kMScaleY]; 840 SkScalar geoDx = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(a*a + c*c)); 841 SkScalar geoDy = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(b*b + d*d)); 842 // This adjusts the "radius" to include the half-pixel border 843 SkScalar offsetDx = SkScalarDiv(geoDx, xRadius); 844 SkScalar offsetDy = SkScalarDiv(geoDy, yRadius); 845 846 SkRect bounds = SkRect::MakeLTRB( 847 center.fX - xRadius - geoDx, 848 center.fY - yRadius - geoDy, 849 center.fX + xRadius + geoDx, 850 center.fY + yRadius + geoDy 851 ); 852 853 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); 854 verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy); 855 verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy); 856 857 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); 858 verts[1].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy); 859 verts[1].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy); 860 861 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); 862 verts[2].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy); 863 verts[2].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy); 864 865 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 866 verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy); 867 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy); 868 869 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); 870 871 return true; 872 } 873 874 /////////////////////////////////////////////////////////////////////////////// 875 876 static const uint16_t gRRectIndices[] = { 877 // corners 878 0, 1, 5, 0, 5, 4, 879 2, 3, 7, 2, 7, 6, 880 8, 9, 13, 8, 13, 12, 881 10, 11, 15, 10, 15, 14, 882 883 // edges 884 1, 2, 6, 1, 6, 5, 885 4, 5, 9, 4, 9, 8, 886 6, 7, 11, 6, 11, 10, 887 9, 10, 14, 9, 14, 13, 888 889 // center 890 // we place this at the end so that we can ignore these indices when rendering stroke-only 891 5, 6, 10, 5, 10, 9 892 }; 893 894 895 GrIndexBuffer* GrOvalRenderer::rRectIndexBuffer(GrGpu* gpu) { 896 if (NULL == fRRectIndexBuffer) { 897 fRRectIndexBuffer = 898 gpu->createIndexBuffer(sizeof(gRRectIndices), false); 899 if (fRRectIndexBuffer) { 900 #ifdef SK_DEBUG 901 bool updated = 902 #endif 903 fRRectIndexBuffer->updateData(gRRectIndices, 904 sizeof(gRRectIndices)); 905 GR_DEBUGASSERT(updated); 906 } 907 } 908 return fRRectIndexBuffer; 909 } 910 911 bool GrOvalRenderer::drawDRRect(GrDrawTarget* target, GrContext* context, bool useAA, 912 const SkRRect& origOuter, const SkRRect& origInner) { 913 bool applyAA = useAA && 914 !target->getDrawState().getRenderTarget()->isMultisampled() && 915 !target->shouldDisableCoverageAAForBlend(); 916 GrDrawState::AutoRestoreEffects are; 917 if (!origInner.isEmpty()) { 918 SkTCopyOnFirstWrite<SkRRect> inner(origInner); 919 if (!context->getMatrix().isIdentity()) { 920 if (!origInner.transform(context->getMatrix(), inner.writable())) { 921 return false; 922 } 923 } 924 GrPrimitiveEdgeType edgeType = applyAA ? 925 kInverseFillAA_GrProcessorEdgeType : 926 kInverseFillBW_GrProcessorEdgeType; 927 GrFragmentProcessor* fp = GrRRectEffect::Create(edgeType, *inner); 928 if (NULL == fp) { 929 return false; 930 } 931 are.set(target->drawState()); 932 target->drawState()->addCoverageProcessor(fp)->unref(); 933 } 934 935 SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle); 936 if (this->drawRRect(target, context, useAA, origOuter, fillRec)) { 937 return true; 938 } 939 940 SkASSERT(!origOuter.isEmpty()); 941 SkTCopyOnFirstWrite<SkRRect> outer(origOuter); 942 if (!context->getMatrix().isIdentity()) { 943 if (!origOuter.transform(context->getMatrix(), outer.writable())) { 944 return false; 945 } 946 } 947 GrPrimitiveEdgeType edgeType = applyAA ? kFillAA_GrProcessorEdgeType : 948 kFillBW_GrProcessorEdgeType; 949 GrFragmentProcessor* effect = GrRRectEffect::Create(edgeType, *outer); 950 if (NULL == effect) { 951 return false; 952 } 953 if (!are.isSet()) { 954 are.set(target->drawState()); 955 } 956 GrDrawState::AutoViewMatrixRestore avmr; 957 if (!avmr.setIdentity(target->drawState())) { 958 return false; 959 } 960 target->drawState()->addCoverageProcessor(effect)->unref(); 961 SkRect bounds = outer->getBounds(); 962 if (applyAA) { 963 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 964 } 965 target->drawRect(bounds, NULL, NULL); 966 return true; 967 } 968 969 bool GrOvalRenderer::drawRRect(GrDrawTarget* target, GrContext* context, bool useAA, 970 const SkRRect& rrect, const SkStrokeRec& stroke) { 971 if (rrect.isOval()) { 972 return this->drawOval(target, context, useAA, rrect.getBounds(), stroke); 973 } 974 975 bool useCoverageAA = useAA && 976 !target->getDrawState().getRenderTarget()->isMultisampled() && 977 !target->shouldDisableCoverageAAForBlend(); 978 979 // only anti-aliased rrects for now 980 if (!useCoverageAA) { 981 return false; 982 } 983 984 const SkMatrix& vm = context->getMatrix(); 985 986 if (!vm.rectStaysRect() || !rrect.isSimple()) { 987 return false; 988 } 989 990 // do any matrix crunching before we reset the draw state for device coords 991 const SkRect& rrectBounds = rrect.getBounds(); 992 SkRect bounds; 993 vm.mapRect(&bounds, rrectBounds); 994 995 SkVector radii = rrect.getSimpleRadii(); 996 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX + 997 vm[SkMatrix::kMSkewY]*radii.fY); 998 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX + 999 vm[SkMatrix::kMScaleY]*radii.fY); 1000 1001 SkStrokeRec::Style style = stroke.getStyle(); 1002 1003 // do (potentially) anisotropic mapping of stroke 1004 SkVector scaledStroke; 1005 SkScalar strokeWidth = stroke.getWidth(); 1006 1007 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || 1008 SkStrokeRec::kHairline_Style == style; 1009 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; 1010 1011 if (hasStroke) { 1012 if (SkStrokeRec::kHairline_Style == style) { 1013 scaledStroke.set(1, 1); 1014 } else { 1015 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + 1016 vm[SkMatrix::kMSkewY])); 1017 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + 1018 vm[SkMatrix::kMScaleY])); 1019 } 1020 1021 // if half of strokewidth is greater than radius, we don't handle that right now 1022 if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) { 1023 return false; 1024 } 1025 } 1026 1027 // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on 1028 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine- 1029 // patch will have fractional coverage. This only matters when the interior is actually filled. 1030 // We could consider falling back to rect rendering here, since a tiny radius is 1031 // indistinguishable from a square corner. 1032 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { 1033 return false; 1034 } 1035 1036 // reset to device coordinates 1037 GrDrawState* drawState = target->drawState(); 1038 GrDrawState::AutoViewMatrixRestore avmr; 1039 if (!avmr.setIdentity(drawState)) { 1040 return false; 1041 } 1042 1043 GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(context->getGpu()); 1044 if (NULL == indexBuffer) { 1045 GrPrintf("Failed to create index buffer!\n"); 1046 return false; 1047 } 1048 1049 // if the corners are circles, use the circle renderer 1050 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) { 1051 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircleVertexAttribs), 1052 sizeof(CircleVertex)); 1053 1054 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); 1055 if (!geo.succeeded()) { 1056 GrPrintf("Failed to get space for vertices!\n"); 1057 return false; 1058 } 1059 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); 1060 1061 SkScalar innerRadius = 0.0f; 1062 SkScalar outerRadius = xRadius; 1063 SkScalar halfWidth = 0; 1064 if (hasStroke) { 1065 if (SkScalarNearlyZero(scaledStroke.fX)) { 1066 halfWidth = SK_ScalarHalf; 1067 } else { 1068 halfWidth = SkScalarHalf(scaledStroke.fX); 1069 } 1070 1071 if (isStrokeOnly) { 1072 innerRadius = xRadius - halfWidth; 1073 } 1074 outerRadius += halfWidth; 1075 bounds.outset(halfWidth, halfWidth); 1076 } 1077 1078 isStrokeOnly = (isStrokeOnly && innerRadius >= 0); 1079 1080 GrGeometryProcessor* effect = CircleEdgeEffect::Create(isStrokeOnly); 1081 drawState->setGeometryProcessor(effect)->unref(); 1082 1083 // The radii are outset for two reasons. First, it allows the shader to simply perform 1084 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the 1085 // verts of the bounding box that is rendered and the outset ensures the box will cover all 1086 // pixels partially covered by the circle. 1087 outerRadius += SK_ScalarHalf; 1088 innerRadius -= SK_ScalarHalf; 1089 1090 // Expand the rect so all the pixels will be captured. 1091 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 1092 1093 SkScalar yCoords[4] = { 1094 bounds.fTop, 1095 bounds.fTop + outerRadius, 1096 bounds.fBottom - outerRadius, 1097 bounds.fBottom 1098 }; 1099 SkScalar yOuterRadii[4] = { 1100 -outerRadius, 1101 0, 1102 0, 1103 outerRadius 1104 }; 1105 for (int i = 0; i < 4; ++i) { 1106 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); 1107 verts->fOffset = SkPoint::Make(-outerRadius, yOuterRadii[i]); 1108 verts->fOuterRadius = outerRadius; 1109 verts->fInnerRadius = innerRadius; 1110 verts++; 1111 1112 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]); 1113 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); 1114 verts->fOuterRadius = outerRadius; 1115 verts->fInnerRadius = innerRadius; 1116 verts++; 1117 1118 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]); 1119 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); 1120 verts->fOuterRadius = outerRadius; 1121 verts->fInnerRadius = innerRadius; 1122 verts++; 1123 1124 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); 1125 verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]); 1126 verts->fOuterRadius = outerRadius; 1127 verts->fInnerRadius = innerRadius; 1128 verts++; 1129 } 1130 1131 // drop out the middle quad if we're stroked 1132 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : 1133 SK_ARRAY_COUNT(gRRectIndices); 1134 target->setIndexSourceToBuffer(indexBuffer); 1135 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bounds); 1136 1137 // otherwise we use the ellipse renderer 1138 } else { 1139 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVertexAttribs), 1140 sizeof(EllipseVertex)); 1141 1142 SkScalar innerXRadius = 0.0f; 1143 SkScalar innerYRadius = 0.0f; 1144 if (hasStroke) { 1145 if (SkScalarNearlyZero(scaledStroke.length())) { 1146 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); 1147 } else { 1148 scaledStroke.scale(SK_ScalarHalf); 1149 } 1150 1151 // we only handle thick strokes for near-circular ellipses 1152 if (scaledStroke.length() > SK_ScalarHalf && 1153 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) { 1154 return false; 1155 } 1156 1157 // we don't handle it if curvature of the stroke is less than curvature of the ellipse 1158 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius || 1159 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) { 1160 return false; 1161 } 1162 1163 // this is legit only if scale & translation (which should be the case at the moment) 1164 if (isStrokeOnly) { 1165 innerXRadius = xRadius - scaledStroke.fX; 1166 innerYRadius = yRadius - scaledStroke.fY; 1167 } 1168 1169 xRadius += scaledStroke.fX; 1170 yRadius += scaledStroke.fY; 1171 bounds.outset(scaledStroke.fX, scaledStroke.fY); 1172 } 1173 1174 isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0); 1175 1176 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); 1177 if (!geo.succeeded()) { 1178 GrPrintf("Failed to get space for vertices!\n"); 1179 return false; 1180 } 1181 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); 1182 1183 GrGeometryProcessor* effect = EllipseEdgeEffect::Create(isStrokeOnly); 1184 drawState->setGeometryProcessor(effect)->unref(); 1185 1186 // Compute the reciprocals of the radii here to save time in the shader 1187 SkScalar xRadRecip = SkScalarInvert(xRadius); 1188 SkScalar yRadRecip = SkScalarInvert(yRadius); 1189 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius); 1190 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius); 1191 1192 // Extend the radii out half a pixel to antialias. 1193 SkScalar xOuterRadius = xRadius + SK_ScalarHalf; 1194 SkScalar yOuterRadius = yRadius + SK_ScalarHalf; 1195 1196 // Expand the rect so all the pixels will be captured. 1197 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 1198 1199 SkScalar yCoords[4] = { 1200 bounds.fTop, 1201 bounds.fTop + yOuterRadius, 1202 bounds.fBottom - yOuterRadius, 1203 bounds.fBottom 1204 }; 1205 SkScalar yOuterOffsets[4] = { 1206 yOuterRadius, 1207 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0 1208 SK_ScalarNearlyZero, 1209 yOuterRadius 1210 }; 1211 1212 for (int i = 0; i < 4; ++i) { 1213 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); 1214 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); 1215 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 1216 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 1217 verts++; 1218 1219 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]); 1220 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]); 1221 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 1222 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 1223 verts++; 1224 1225 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]); 1226 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]); 1227 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 1228 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 1229 verts++; 1230 1231 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); 1232 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); 1233 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 1234 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 1235 verts++; 1236 } 1237 1238 // drop out the middle quad if we're stroked 1239 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : 1240 SK_ARRAY_COUNT(gRRectIndices); 1241 target->setIndexSourceToBuffer(indexBuffer); 1242 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bounds); 1243 } 1244 1245 return true; 1246 } 1247