Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: src/gpu/GrOvalRenderer.cpp

Issue 23701013: Add device-independent rendering of ovals, take two. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: A little more prettyprint Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « include/gpu/GrOvalRenderer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrOvalRenderer.h" 8 #include "GrOvalRenderer.h"
9 9
10 #include "GrEffect.h" 10 #include "GrEffect.h"
(...skipping 19 matching lines...) Expand all
30 SkScalar fInnerRadius; 30 SkScalar fInnerRadius;
31 }; 31 };
32 32
33 struct EllipseVertex { 33 struct EllipseVertex {
34 GrPoint fPos; 34 GrPoint fPos;
35 GrPoint fOffset; 35 GrPoint fOffset;
36 GrPoint fOuterRadii; 36 GrPoint fOuterRadii;
37 GrPoint fInnerRadii; 37 GrPoint fInnerRadii;
38 }; 38 };
39 39
40 struct DIEllipseVertex {
41 GrPoint fPos;
42 GrPoint fOuterOffset;
43 GrPoint fInnerOffset;
44 };
45
40 inline bool circle_stays_circle(const SkMatrix& m) { 46 inline bool circle_stays_circle(const SkMatrix& m) {
41 return m.isSimilarity(); 47 return m.isSimilarity();
42 } 48 }
43 49
44 } 50 }
45 51
46 /////////////////////////////////////////////////////////////////////////////// 52 ///////////////////////////////////////////////////////////////////////////////
47 53
48 /** 54 /**
49 * The output of this effect is a modulation of the input color and coverage for a circle, 55 * The output of this effect is a modulation of the input color and coverage for a circle,
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 291
286 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random, 292 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random,
287 GrContext* context, 293 GrContext* context,
288 const GrDrawTargetCaps&, 294 const GrDrawTargetCaps&,
289 GrTexture* textures[]) { 295 GrTexture* textures[]) {
290 return EllipseEdgeEffect::Create(random->nextBool()); 296 return EllipseEdgeEffect::Create(random->nextBool());
291 } 297 }
292 298
293 /////////////////////////////////////////////////////////////////////////////// 299 ///////////////////////////////////////////////////////////////////////////////
294 300
301 /**
302 * The output of this effect is a modulation of the input color and coverage for an ellipse,
303 * specified as a 2D offset from center for both the outer and inner paths (if s troked). The
304 * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge c orrected by
305 * using differentials.
306 *
307 * The result is device-independent and can be used with any affine matrix.
308 */
309
310 class DIEllipseEdgeEffect : public GrEffect {
311 public:
312 enum Mode { kStroke = 0, kHairline, kFill };
313
314 static GrEffectRef* Create(Mode mode) {
315 GR_CREATE_STATIC_EFFECT(gEllipseStrokeEdge, DIEllipseEdgeEffect, (kStrok e));
316 GR_CREATE_STATIC_EFFECT(gEllipseHairlineEdge, DIEllipseEdgeEffect, (kHai rline));
317 GR_CREATE_STATIC_EFFECT(gEllipseFillEdge, DIEllipseEdgeEffect, (kFill));
318
319 if (kStroke == mode) {
320 gEllipseStrokeEdge->ref();
321 return gEllipseStrokeEdge;
322 } else if (kHairline == mode) {
323 gEllipseHairlineEdge->ref();
324 return gEllipseHairlineEdge;
325 } else {
326 gEllipseFillEdge->ref();
327 return gEllipseFillEdge;
328 }
329 }
330
331 virtual void getConstantColorComponents(GrColor* color,
332 uint32_t* validFlags) const SK_OVERR IDE {
333 *validFlags = 0;
334 }
335
336 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
337 return GrTBackendEffectFactory<DIEllipseEdgeEffect>::getInstance();
338 }
339
340 virtual ~DIEllipseEdgeEffect() {}
341
342 static const char* Name() { return "DIEllipseEdge"; }
343
344 inline Mode getMode() const { return fMode; }
345
346 class GLEffect : public GrGLEffect {
347 public:
348 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
349 : INHERITED (factory) {}
350
351 virtual void emitCode(GrGLShaderBuilder* builder,
352 const GrDrawEffect& drawEffect,
353 EffectKey key,
354 const char* outputColor,
355 const char* inputColor,
356 const TextureSamplerArray& samplers) SK_OVERRIDE {
357 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertex Builder();
358 SkASSERT(NULL != vertexBuilder);
359
360 const DIEllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<DIE llipseEdgeEffect>();
361
362 SkAssertResult(builder->enableFeature(
363 GrGLShaderBuilder::kStandardDeriva tives_GLSLFeature));
364
365 const char *vsOffsetName, *fsOffsetName;
366 vertexBuilder->addVarying(kVec4f_GrSLType, "EllipseOffsets",
367 &vsOffsetName, &fsOffsetName);
368 const SkString* attr0Name =
369 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttrib Indices()[0]);
370 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name ->c_str());
371
372 // for outer curve
373 builder->fsCodeAppendf("\tvec2 scaledOffset = %s.xy;\n", fsOffsetNam e);
374 builder->fsCodeAppend("\tfloat test = dot(scaledOffset, scaledOffset ) - 1.0;\n");
375 builder->fsCodeAppendf("\tvec4 duvdx = dFdx(%s);\n", fsOffsetName);
376 builder->fsCodeAppendf("\tvec4 duvdy = dFdy(%s);\n", fsOffsetName);
377 builder->fsCodeAppendf("\tvec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s .y*duvdx.y,\n"
378 "\t 2.0*%s.x*duvdy.x + 2.0*%s .y*duvdy.y);\n",
379 fsOffsetName, fsOffsetName, fsOffsetName, fsO ffsetName);
380
381 builder->fsCodeAppend("\tfloat grad_dot = dot(grad, grad);\n");
382 // we need to clamp the length^2 of the gradiant vector to a non-zer o value, because
383 // on the Nexus 4 the undefined result of inversesqrt(0) drops out a n entire tile
384 // TODO: restrict this to Adreno-only
385 builder->fsCodeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n");
386 builder->fsCodeAppend("\tfloat invlen = inversesqrt(grad_dot);\n");
387 if (kHairline == ellipseEffect.getMode()) {
388 // can probably do this with one step
389 builder->fsCodeAppend("\tfloat edgeAlpha = clamp(1.0-test*invlen , 0.0, 1.0);\n");
390 builder->fsCodeAppend("\tedgeAlpha *= clamp(1.0+test*invlen, 0.0 , 1.0);\n");
391 } else {
392 builder->fsCodeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen , 0.0, 1.0);\n");
393 }
394
395 // for inner curve
396 if (kStroke == ellipseEffect.getMode()) {
397 builder->fsCodeAppendf("\tscaledOffset = %s.zw;\n", fsOffsetName );
398 builder->fsCodeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n");
399 builder->fsCodeAppendf("\tgrad = vec2(2.0*%s.z*duvdx.z + 2.0*%s. w*duvdx.w,\n"
400 "\t 2.0*%s.z*duvdy.z + 2.0*%s. w*duvdy.w);\n",
401 fsOffsetName, fsOffsetName, fsOffsetName, fsOffsetName);
402 builder->fsCodeAppend("\tinvlen = inversesqrt(dot(grad, grad));\ n");
403 builder->fsCodeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0 , 1.0);\n");
404 }
405
406 SkString modulate;
407 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
408 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() );
409 }
410
411 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) {
412 const DIEllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<DIE llipseEdgeEffect>();
413
414 return ellipseEffect.getMode();
415 }
416
417 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE {
418 }
419
420 private:
421 typedef GrGLEffect INHERITED;
422 };
423
424 private:
425 DIEllipseEdgeEffect(Mode mode) : GrEffect() {
426 this->addVertexAttrib(kVec4f_GrSLType);
427 fMode = mode;
428 }
429
430 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
431 const DIEllipseEdgeEffect& eee = CastEffect<DIEllipseEdgeEffect>(other);
432 return eee.fMode == fMode;
433 }
434
435 Mode fMode;
436
437 GR_DECLARE_EFFECT_TEST;
438
439 typedef GrEffect INHERITED;
440 };
441
442 GR_DEFINE_EFFECT_TEST(DIEllipseEdgeEffect);
443
444 GrEffectRef* DIEllipseEdgeEffect::TestCreate(SkMWCRandom* random,
445 GrContext* context,
446 const GrDrawTargetCaps&,
447 GrTexture* textures[]) {
448 return DIEllipseEdgeEffect::Create((Mode)(random->nextRangeU(0,2)));
449 }
450
451 ///////////////////////////////////////////////////////////////////////////////
452
295 void GrOvalRenderer::reset() { 453 void GrOvalRenderer::reset() {
296 GrSafeSetNull(fRRectIndexBuffer); 454 GrSafeSetNull(fRRectIndexBuffer);
297 } 455 }
298 456
299 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, bo ol useAA, 457 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, bo ol useAA,
300 const SkRect& oval, const SkStrokeRec& stroke) 458 const SkRect& oval, const SkStrokeRec& stroke)
301 { 459 {
302 if (!useAA) { 460 if (!useAA) {
303 return false; 461 return false;
304 } 462 }
305 463
306 const SkMatrix& vm = context->getMatrix(); 464 const SkMatrix& vm = context->getMatrix();
307 465
308 // we can draw circles 466 // we can draw circles
309 if (SkScalarNearlyEqual(oval.width(), oval.height()) 467 if (SkScalarNearlyEqual(oval.width(), oval.height())
310 && circle_stays_circle(vm)) { 468 && circle_stays_circle(vm)) {
311 this->drawCircle(target, useAA, oval, stroke); 469 this->drawCircle(target, useAA, oval, stroke);
312 470 // if we have shader derivative support, render as device-independent
313 // and axis-aligned ellipses only 471 } else if (target->caps()->shaderDerivativeSupport()) {
bsalomon 2013/09/04 20:51:16 Is it better to prefer the circle renderer or shou
472 return this->drawDIEllipse(target, useAA, oval, stroke);
473 // otherwise axis-aligned ellipses only
314 } else if (vm.rectStaysRect()) { 474 } else if (vm.rectStaysRect()) {
315 return this->drawEllipse(target, useAA, oval, stroke); 475 return this->drawEllipse(target, useAA, oval, stroke);
316
317 } else { 476 } else {
318 return false; 477 return false;
319 } 478 }
320 479
321 return true; 480 return true;
322 } 481 }
323 482
324 namespace {
325
326 /////////////////////////////////////////////////////////////////////////////// 483 ///////////////////////////////////////////////////////////////////////////////
327 484
328 // position + edge 485 // position + edge
329 extern const GrVertexAttrib gCircleVertexAttribs[] = { 486 extern const GrVertexAttrib gCircleVertexAttribs[] = {
330 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, 487 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
331 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} 488 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
332 }; 489 };
333 490
334 };
335
336 void GrOvalRenderer::drawCircle(GrDrawTarget* target, 491 void GrOvalRenderer::drawCircle(GrDrawTarget* target,
337 bool useAA, 492 bool useAA,
338 const SkRect& circle, 493 const SkRect& circle,
339 const SkStrokeRec& stroke) 494 const SkStrokeRec& stroke)
340 { 495 {
341 GrDrawState* drawState = target->drawState(); 496 GrDrawState* drawState = target->drawState();
342 497
343 const SkMatrix& vm = drawState->getViewMatrix(); 498 const SkMatrix& vm = drawState->getViewMatrix();
344 GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY()); 499 GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY());
345 vm.mapPoints(&center, 1); 500 vm.mapPoints(&center, 1);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 572 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
418 verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius); 573 verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius);
419 verts[3].fOuterRadius = outerRadius; 574 verts[3].fOuterRadius = outerRadius;
420 verts[3].fInnerRadius = innerRadius; 575 verts[3].fInnerRadius = innerRadius;
421 576
422 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); 577 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
423 } 578 }
424 579
425 /////////////////////////////////////////////////////////////////////////////// 580 ///////////////////////////////////////////////////////////////////////////////
426 581
427 namespace { 582 // position + offset + 1/radii
428
429 // position + edge
430 extern const GrVertexAttrib gEllipseVertexAttribs[] = { 583 extern const GrVertexAttrib gEllipseVertexAttribs[] = {
431 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindi ng}, 584 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindi ng},
432 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding }, 585 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
433 {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint), kEffect_GrVertexAttribBinding } 586 {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
434 }; 587 };
435 588
589 // position + offsets
590 extern const GrVertexAttrib gDIEllipseVertexAttribs[] = {
591 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindi ng},
592 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
436 }; 593 };
437 594
438 bool GrOvalRenderer::drawEllipse(GrDrawTarget* target, 595 bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
439 bool useAA, 596 bool useAA,
440 const SkRect& ellipse, 597 const SkRect& ellipse,
441 const SkStrokeRec& stroke) 598 const SkStrokeRec& stroke)
442 { 599 {
443 GrDrawState* drawState = target->drawState(); 600 GrDrawState* drawState = target->drawState();
444 #ifdef SK_DEBUG 601 #ifdef SK_DEBUG
445 { 602 {
(...skipping 16 matching lines...) Expand all
462 619
463 // do (potentially) anisotropic mapping of stroke 620 // do (potentially) anisotropic mapping of stroke
464 SkVector scaledStroke; 621 SkVector scaledStroke;
465 SkScalar strokeWidth = stroke.getWidth(); 622 SkScalar strokeWidth = stroke.getWidth();
466 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat rix::kMSkewY])); 623 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat rix::kMSkewY]));
467 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr ix::kMScaleY])); 624 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr ix::kMScaleY]));
468 625
469 SkStrokeRec::Style style = stroke.getStyle(); 626 SkStrokeRec::Style style = stroke.getStyle();
470 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); 627 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style);
471 628
472 SkScalar innerXRadius = 0.0f; 629 SkScalar innerXRadius = 0;
473 SkScalar innerYRadius = 0.0f; 630 SkScalar innerYRadius = 0;
474 if (SkStrokeRec::kFill_Style != style) { 631 if (SkStrokeRec::kFill_Style != style) {
475 if (SkScalarNearlyZero(scaledStroke.length())) { 632 if (SkScalarNearlyZero(scaledStroke.length())) {
476 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); 633 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
477 } else { 634 } else {
478 scaledStroke.scale(SK_ScalarHalf); 635 scaledStroke.scale(SK_ScalarHalf);
479 } 636 }
480 637
481 // we only handle thick strokes for near-circular ellipses 638 // we only handle thick strokes for near-circular ellipses
482 if (scaledStroke.length() > SK_ScalarHalf && 639 if (scaledStroke.length() > SK_ScalarHalf &&
483 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius) ) { 640 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius) ) {
(...skipping 29 matching lines...) Expand all
513 GrPrintf("Failed to get space for vertices!\n"); 670 GrPrintf("Failed to get space for vertices!\n");
514 return false; 671 return false;
515 } 672 }
516 673
517 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); 674 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
518 675
519 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked && 676 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked &&
520 innerXRadius > 0 && innerYRa dius > 0); 677 innerXRadius > 0 && innerYRa dius > 0);
521 678
522 static const int kEllipseCenterAttrIndex = 1; 679 static const int kEllipseCenterAttrIndex = 1;
523 static const int kEllipseEdgeAttrIndex = 2; 680 drawState->addCoverageEffect(effect, kEllipseCenterAttrIndex)->unref();
524 drawState->addCoverageEffect(effect, kEllipseCenterAttrIndex, kEllipseEdgeAt trIndex)->unref();
525 681
526 // Compute the reciprocals of the radii here to save time in the shader 682 // Compute the reciprocals of the radii here to save time in the shader
527 SkScalar xRadRecip = SkScalarInvert(xRadius); 683 SkScalar xRadRecip = SkScalarInvert(xRadius);
528 SkScalar yRadRecip = SkScalarInvert(yRadius); 684 SkScalar yRadRecip = SkScalarInvert(yRadius);
529 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius); 685 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
530 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius); 686 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
531 687
532 // We've extended the outer x radius out half a pixel to antialias. 688 // We've extended the outer x radius out half a pixel to antialias.
533 // This will also expand the rect so all the pixels will be captured. 689 // This will also expand the rect so all the pixels will be captured.
534 // TODO: Consider if we should use sqrt(2)/2 instead 690 // TODO: Consider if we should use sqrt(2)/2 instead
(...skipping 25 matching lines...) Expand all
560 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 716 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
561 verts[3].fOffset = SkPoint::Make(xRadius, yRadius); 717 verts[3].fOffset = SkPoint::Make(xRadius, yRadius);
562 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 718 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
563 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 719 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
564 720
565 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); 721 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
566 722
567 return true; 723 return true;
568 } 724 }
569 725
726 bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
727 bool useAA,
728 const SkRect& ellipse,
729 const SkStrokeRec& stroke)
730 {
731 GrDrawState* drawState = target->drawState();
732 const SkMatrix& vm = drawState->getViewMatrix();
733
734 GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY());
735 SkScalar xRadius = SkScalarHalf(ellipse.width());
736 SkScalar yRadius = SkScalarHalf(ellipse.height());
737
738 SkStrokeRec::Style style = stroke.getStyle();
739 DIEllipseEdgeEffect::Mode mode = (SkStrokeRec::kStroke_Style == style) ?
740 DIEllipseEdgeEffect::kStroke :
741 (SkStrokeRec::kHairline_Style == style) ?
742 DIEllipseEdgeEffect::kHairline : DIEllipseEd geEffect::kFill;
743
744 SkScalar innerXRadius = 0;
745 SkScalar innerYRadius = 0;
746 if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != sty le) {
747 SkScalar strokeWidth = stroke.getWidth();
748
749 if (SkScalarNearlyZero(strokeWidth)) {
750 strokeWidth = SK_ScalarHalf;
751 } else {
752 strokeWidth *= SK_ScalarHalf;
753 }
754
755 // we only handle thick strokes for near-circular ellipses
756 if (strokeWidth > SK_ScalarHalf &&
757 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius) ) {
758 return false;
759 }
760
761 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
762 if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
763 strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
764 return false;
765 }
766
767 // set inner radius (if needed)
768 if (SkStrokeRec::kStroke_Style == style) {
769 innerXRadius = xRadius - strokeWidth;
770 innerYRadius = yRadius - strokeWidth;
771 }
772
773 xRadius += strokeWidth;
774 yRadius += strokeWidth;
775 }
776 if (DIEllipseEdgeEffect::kStroke == mode) {
777 mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kSt roke :
778 DIEllipseEdgeEffect::kFi ll;
779 }
780 SkScalar innerRatioX = SkScalarDiv(xRadius, innerXRadius);
781 SkScalar innerRatioY = SkScalarDiv(yRadius, innerYRadius);
782
783 drawState->setVertexAttribs<gDIEllipseVertexAttribs>(SK_ARRAY_COUNT(gDIEllip seVertexAttribs));
784 SkASSERT(sizeof(DIEllipseVertex) == drawState->getVertexSize());
785
786 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
787 if (!geo.succeeded()) {
788 GrPrintf("Failed to get space for vertices!\n");
789 return false;
790 }
791
792 DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(geo.vertices());
793
794 GrEffectRef* effect = DIEllipseEdgeEffect::Create(mode);
795
796 static const int kEllipseOuterOffsetAttrIndex = 1;
797 static const int kEllipseInnerOffsetAttrIndex = 2;
798 drawState->addCoverageEffect(effect, kEllipseOuterOffsetAttrIndex,
799 kEllipseInnerOffsetAttrIndex)->unref();
800
801 // This expands the outer rect so that after CTM we end up with a half-pixel border
802 SkScalar a = vm[SkMatrix::kMScaleX];
803 SkScalar b = vm[SkMatrix::kMSkewX];
804 SkScalar c = vm[SkMatrix::kMSkewY];
805 SkScalar d = vm[SkMatrix::kMScaleY];
806 SkScalar geoDx = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(a*a + c*c));
807 SkScalar geoDy = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(b*b + d*d));
808 // This adjusts the "radius" to include the half-pixel border
809 SkScalar offsetDx = SkScalarDiv(geoDx, xRadius);
810 SkScalar offsetDy = SkScalarDiv(geoDy, yRadius);
811
812 SkRect bounds = SkRect::MakeLTRB(
813 center.fX - xRadius - geoDx,
814 center.fY - yRadius - geoDy,
815 center.fX + xRadius + geoDx,
816 center.fY + yRadius + geoDy
817 );
818
819 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
820 verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
821 verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
822
823 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
824 verts[1].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
825 verts[1].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
826
827 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
828 verts[2].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
829 verts[2].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
830
831 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
832 verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
833 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
834
835 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
836
837 return true;
838 }
839
570 /////////////////////////////////////////////////////////////////////////////// 840 ///////////////////////////////////////////////////////////////////////////////
571 841
572 static const uint16_t gRRectIndices[] = { 842 static const uint16_t gRRectIndices[] = {
573 // corners 843 // corners
574 0, 1, 5, 0, 5, 4, 844 0, 1, 5, 0, 5, 4,
575 2, 3, 7, 2, 7, 6, 845 2, 3, 7, 2, 7, 6,
576 8, 9, 13, 8, 13, 12, 846 8, 9, 13, 8, 13, 12,
577 10, 11, 15, 10, 15, 14, 847 10, 11, 15, 10, 15, 14,
578 848
579 // edges 849 // edges
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 halfWidth = SkScalarHalf(scaledStroke.fX); 956 halfWidth = SkScalarHalf(scaledStroke.fX);
687 } 957 }
688 958
689 if (isStroked) { 959 if (isStroked) {
690 innerRadius = xRadius - halfWidth; 960 innerRadius = xRadius - halfWidth;
691 } 961 }
692 outerRadius += halfWidth; 962 outerRadius += halfWidth;
693 bounds.outset(halfWidth, halfWidth); 963 bounds.outset(halfWidth, halfWidth);
694 } 964 }
695 965
696 isStroked = (isStroked && innerRadius > 0); 966 isStroked = (isStroked && innerRadius > 0);
697 967
698 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked); 968 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
699 static const int kCircleEdgeAttrIndex = 1; 969 static const int kCircleEdgeAttrIndex = 1;
700 drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref(); 970 drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref();
701 971
702 // The radii are outset for two reasons. First, it allows the shader to simply perform 972 // The radii are outset for two reasons. First, it allows the shader to simply perform
703 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the 973 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
704 // verts of the bounding box that is rendered and the outset ensures the box will cover all 974 // verts of the bounding box that is rendered and the outset ensures the box will cover all
705 // pixels partially covered by the circle. 975 // pixels partially covered by the circle.
706 outerRadius += SK_ScalarHalf; 976 outerRadius += SK_ScalarHalf;
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
782 if (isStroked) { 1052 if (isStroked) {
783 innerXRadius = xRadius - scaledStroke.fX; 1053 innerXRadius = xRadius - scaledStroke.fX;
784 innerYRadius = yRadius - scaledStroke.fY; 1054 innerYRadius = yRadius - scaledStroke.fY;
785 } 1055 }
786 1056
787 xRadius += scaledStroke.fX; 1057 xRadius += scaledStroke.fX;
788 yRadius += scaledStroke.fY; 1058 yRadius += scaledStroke.fY;
789 bounds.outset(scaledStroke.fX, scaledStroke.fY); 1059 bounds.outset(scaledStroke.fX, scaledStroke.fY);
790 } 1060 }
791 1061
792 isStroked = (isStroked && innerXRadius > 0 && innerYRadius > 0); 1062 isStroked = (isStroked && innerXRadius > 0 && innerYRadius > 0);
793 1063
794 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); 1064 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
795 if (!geo.succeeded()) { 1065 if (!geo.succeeded()) {
796 GrPrintf("Failed to get space for vertices!\n"); 1066 GrPrintf("Failed to get space for vertices!\n");
797 return false; 1067 return false;
798 } 1068 }
799 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); 1069 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
800 1070
801 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); 1071 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
802 static const int kEllipseOffsetAttrIndex = 1; 1072 static const int kEllipseOffsetAttrIndex = 1;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 } 1127 }
858 1128
859 // drop out the middle quad if we're stroked 1129 // drop out the middle quad if we're stroked
860 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices); 1130 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices);
861 target->setIndexSourceToBuffer(indexBuffer); 1131 target->setIndexSourceToBuffer(indexBuffer);
862 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds); 1132 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds);
863 } 1133 }
864 1134
865 return true; 1135 return true;
866 } 1136 }
OLDNEW
« no previous file with comments | « include/gpu/GrOvalRenderer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698