OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 "GrRRectEffect.h" | 8 #include "GrRRectEffect.h" |
9 | 9 |
10 #include "GrConvexPolyEffect.h" | 10 #include "GrConvexPolyEffect.h" |
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 virtual void emitCode(EmitArgs&) override; | 491 virtual void emitCode(EmitArgs&) override; |
492 | 492 |
493 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor
KeyBuilder*); | 493 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor
KeyBuilder*); |
494 | 494 |
495 protected: | 495 protected: |
496 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override
; | 496 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override
; |
497 | 497 |
498 private: | 498 private: |
499 GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; | 499 GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; |
500 GrGLSLProgramDataManager::UniformHandle fInvRadiiSqdUniform; | 500 GrGLSLProgramDataManager::UniformHandle fInvRadiiSqdUniform; |
501 SkRRect fPrevRRect; | 501 GrGLSLProgramDataManager::UniformHandle fScaleUniform; |
| 502 SkRRect fPrevRRect; |
502 typedef GrGLSLFragmentProcessor INHERITED; | 503 typedef GrGLSLFragmentProcessor INHERITED; |
503 }; | 504 }; |
504 | 505 |
505 GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrProcessor& effect) { | 506 GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrProcessor& effect) { |
506 fPrevRRect.setEmpty(); | 507 fPrevRRect.setEmpty(); |
507 } | 508 } |
508 | 509 |
509 void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { | 510 void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { |
510 const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>(); | 511 const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>(); |
511 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | 512 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
(...skipping 11 matching lines...) Expand all Loading... |
523 // to that corner. This means that points near the interior near the rrect t
op edge will have | 524 // to that corner. This means that points near the interior near the rrect t
op edge will have |
524 // a vector that points straight up for both the TL left and TR corners. Com
puting an | 525 // a vector that points straight up for both the TL left and TR corners. Com
puting an |
525 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, | 526 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, |
526 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of | 527 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of |
527 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dii > 0.5 they will | 528 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dii > 0.5 they will |
528 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. | 529 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. |
529 // | 530 // |
530 // The code below is a simplified version of the above that performs maxs on
the vector | 531 // The code below is a simplified version of the above that performs maxs on
the vector |
531 // components before computing distances and alpha values so that only one d
istance computation | 532 // components before computing distances and alpha values so that only one d
istance computation |
532 // need be computed to determine the min alpha. | 533 // need be computed to determine the min alpha. |
533 fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragm
entPos); | 534 fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos
); |
534 fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, re
ctName); | 535 fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName
); |
| 536 |
| 537 // If we're on a device with a "real" mediump then we'll do the distance com
putation in a space |
| 538 // that is normalized by the largest radius. The scale uniform will be scale
, 1/scale. The |
| 539 // radii uniform values are already in this normalized space. |
| 540 const char* scaleName = nullptr; |
| 541 if (args.fGLSLCaps->floatPrecisionVaries()) { |
| 542 fScaleUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragme
nt_Visibility, |
| 543 kVec2f_GrSLType, kDefault_GrS
LPrecision, |
| 544 "scale", &scaleName); |
| 545 } |
| 546 |
535 // The uniforms with the inv squared radii are highp to prevent underflow. | 547 // The uniforms with the inv squared radii are highp to prevent underflow. |
536 switch (erre.getRRect().getType()) { | 548 switch (erre.getRRect().getType()) { |
537 case SkRRect::kSimple_Type: { | 549 case SkRRect::kSimple_Type: { |
538 const char *invRadiiXYSqdName; | 550 const char *invRadiiXYSqdName; |
539 fInvRadiiSqdUniform = uniformHandler->addUniform( | 551 fInvRadiiSqdUniform = uniformHandler->addUniform( |
540 GrGLSLUniformHandler::k
Fragment_Visibility, | 552 GrGLSLUniformHandler::k
Fragment_Visibility, |
541 kVec2f_GrSLType, kHigh_
GrSLPrecision, | 553 kVec2f_GrSLType, kDefau
lt_GrSLPrecision, |
542 "invRadiiXY", | 554 "invRadiiXY", |
543 &invRadiiXYSqdName); | 555 &invRadiiXYSqdName); |
544 fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n
"); | 556 fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); |
| 557 if (scaleName) { |
| 558 fragBuilder->codeAppendf("dxy *= %s.y;", scaleName); |
| 559 } |
545 // Z is the x/y offsets divided by squared radii. | 560 // Z is the x/y offsets divided by squared radii. |
546 fragBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdNa
me); | 561 fragBuilder->codeAppendf("vec2 Z = dxy * %s.xy;", invRadiiXYSqdName)
; |
547 break; | 562 break; |
548 } | 563 } |
549 case SkRRect::kNinePatch_Type: { | 564 case SkRRect::kNinePatch_Type: { |
550 const char *invRadiiLTRBSqdName; | 565 const char *invRadiiLTRBSqdName; |
551 fInvRadiiSqdUniform = uniformHandler->addUniform( | 566 fInvRadiiSqdUniform = uniformHandler->addUniform( |
552 GrGLSLUniformHandler::k
Fragment_Visibility, | 567 GrGLSLUniformHandler::k
Fragment_Visibility, |
553 kVec4f_GrSLType, kHigh_
GrSLPrecision, | 568 kVec4f_GrSLType, kDefau
lt_GrSLPrecision, |
554 "invRadiiLTRB", | 569 "invRadiiLTRB", |
555 &invRadiiLTRBSqdName); | 570 &invRadiiLTRBSqdName); |
556 fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n
"); | 571 if (scaleName) { |
| 572 fragBuilder->codeAppendf("dxy0 *= %s.y;", scaleName); |
| 573 fragBuilder->codeAppendf("dxy1 *= %s.y;", scaleName); |
| 574 } |
| 575 fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); |
557 // Z is the x/y offsets divided by squared radii. We only care about
the (at most) one | 576 // Z is the x/y offsets divided by squared radii. We only care about
the (at most) one |
558 // corner where both the x and y offsets are positive, hence the max
es. (The inverse | 577 // corner where both the x and y offsets are positive, hence the max
es. (The inverse |
559 // squared radii will always be positive.) | 578 // squared radii will always be positive.) |
560 fragBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 *
%s.zw), 0.0);\n", | 579 fragBuilder->codeAppendf("vec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.z
w), 0.0);", |
561 invRadiiLTRBSqdName, invRadiiLTRBSqdName); | 580 invRadiiLTRBSqdName, invRadiiLTRBSqdName); |
| 581 |
562 break; | 582 break; |
563 } | 583 } |
564 default: | 584 default: |
565 SkFAIL("RRect should always be simple or nine-patch."); | 585 SkFAIL("RRect should always be simple or nine-patch."); |
566 } | 586 } |
567 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. | 587 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. |
568 fragBuilder->codeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n"); | 588 fragBuilder->codeAppend("float implicit = dot(Z, dxy) - 1.0;"); |
569 // grad_dot is the squared length of the gradient of the implicit. | 589 // grad_dot is the squared length of the gradient of the implicit. |
570 fragBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n"); | 590 fragBuilder->codeAppend("float grad_dot = 4.0 * dot(Z, Z);"); |
571 // avoid calling inversesqrt on zero. | 591 // avoid calling inversesqrt on zero. |
572 fragBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n"); | 592 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);"); |
573 fragBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(gra
d_dot);\n"); | 593 fragBuilder->codeAppend("float approx_dist = implicit * inversesqrt(grad_dot
);"); |
| 594 if (scaleName) { |
| 595 fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName); |
| 596 } |
574 | 597 |
575 if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) { | 598 if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) { |
576 fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0,
1.0);\n"); | 599 fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0
);"); |
577 } else { | 600 } else { |
578 fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0,
1.0);\n"); | 601 fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0
);"); |
579 } | 602 } |
580 | 603 |
581 fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, | 604 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, |
582 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha
")).c_str()); | 605 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha
")).c_str()); |
583 } | 606 } |
584 | 607 |
585 void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrGLSLCaps
&, | 608 void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrGLSLCaps
&, |
586 GrProcessorKeyBuilder* b) { | 609 GrProcessorKeyBuilder* b) { |
587 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); | 610 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); |
588 GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3)); | 611 GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3)); |
589 b->add32(erre.getRRect().getType() | erre.getEdgeType() << 3); | 612 b->add32(erre.getRRect().getType() | erre.getEdgeType() << 3); |
590 } | 613 } |
591 | 614 |
592 void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, | 615 void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, |
593 const GrProcessor& effect) { | 616 const GrProcessor& effect) { |
594 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); | 617 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); |
595 const SkRRect& rrect = erre.getRRect(); | 618 const SkRRect& rrect = erre.getRRect(); |
| 619 // If we're using a scale factor to work around precision issues, choose the
largest radius |
| 620 // as the scale factor. The inv radii need to be pre-adjusted by the scale f
actor. |
596 if (rrect != fPrevRRect) { | 621 if (rrect != fPrevRRect) { |
597 SkRect rect = rrect.getBounds(); | 622 SkRect rect = rrect.getBounds(); |
598 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); | 623 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); |
599 SkASSERT(r0.fX >= kRadiusMin); | 624 SkASSERT(r0.fX >= kRadiusMin); |
600 SkASSERT(r0.fY >= kRadiusMin); | 625 SkASSERT(r0.fY >= kRadiusMin); |
601 switch (erre.getRRect().getType()) { | 626 switch (erre.getRRect().getType()) { |
602 case SkRRect::kSimple_Type: | 627 case SkRRect::kSimple_Type: |
603 rect.inset(r0.fX, r0.fY); | 628 rect.inset(r0.fX, r0.fY); |
604 pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), | 629 if (fScaleUniform.isValid()) { |
605 1.f / (r0.fY * r0.fY)); | 630 if (r0.fX > r0.fY) { |
| 631 pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) /
(r0.fY * r0.fY)); |
| 632 pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX); |
| 633 } else { |
| 634 pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.f
X * r0.fX), 1.f); |
| 635 pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY); |
| 636 } |
| 637 } else { |
| 638 pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), |
| 639 1.f / (r0.fY * r0.fY)); |
| 640 } |
606 break; | 641 break; |
607 case SkRRect::kNinePatch_Type: { | 642 case SkRRect::kNinePatch_Type: { |
608 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); | 643 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); |
609 SkASSERT(r1.fX >= kRadiusMin); | 644 SkASSERT(r1.fX >= kRadiusMin); |
610 SkASSERT(r1.fY >= kRadiusMin); | 645 SkASSERT(r1.fY >= kRadiusMin); |
611 rect.fLeft += r0.fX; | 646 rect.fLeft += r0.fX; |
612 rect.fTop += r0.fY; | 647 rect.fTop += r0.fY; |
613 rect.fRight -= r1.fX; | 648 rect.fRight -= r1.fX; |
614 rect.fBottom -= r1.fY; | 649 rect.fBottom -= r1.fY; |
615 pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), | 650 if (fScaleUniform.isValid()) { |
616 1.f / (r0.fY * r0.fY), | 651 float scale = SkTMax(SkTMax(r0.fX, r0.fY), SkTMax(r1.fX, r1.
fY)); |
617 1.f / (r1.fX * r1.fX), | 652 float scaleSqd = scale * scale; |
618 1.f / (r1.fY * r1.fY)); | 653 pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX), |
| 654 scaleSqd / (r0.fY * r0.fY), |
| 655 scaleSqd / (r1.fX * r1.fX), |
| 656 scaleSqd / (r1.fY * r1.fY))
; |
| 657 pdman.set2f(fScaleUniform, scale, 1.f / scale); |
| 658 } else { |
| 659 pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), |
| 660 1.f / (r0.fY * r0.fY), |
| 661 1.f / (r1.fX * r1.fX), |
| 662 1.f / (r1.fY * r1.fY)); |
| 663 } |
619 break; | 664 break; |
620 } | 665 } |
621 default: | 666 default: |
622 SkFAIL("RRect should always be simple or nine-patch."); | 667 SkFAIL("RRect should always be simple or nine-patch."); |
623 } | 668 } |
624 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.
fBottom); | 669 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.
fBottom); |
625 fPrevRRect = rrect; | 670 fPrevRRect = rrect; |
626 } | 671 } |
627 } | 672 } |
628 | 673 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
728 if (rrect.isNinePatch()) { | 773 if (rrect.isNinePatch()) { |
729 return EllipticalRRectEffect::Create(edgeType, rrect); | 774 return EllipticalRRectEffect::Create(edgeType, rrect); |
730 } | 775 } |
731 return nullptr; | 776 return nullptr; |
732 } | 777 } |
733 } | 778 } |
734 } | 779 } |
735 | 780 |
736 return nullptr; | 781 return nullptr; |
737 } | 782 } |
OLD | NEW |