Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | List of all members
EllipticalRRectEffect::Impl Class Reference
Inheritance diagram for EllipticalRRectEffect::Impl:
GrFragmentProcessor::ProgramImpl

Public Member Functions

void emitCode (EmitArgs &) override
 
- Public Member Functions inherited from GrFragmentProcessor::ProgramImpl
 ProgramImpl ()=default
 
virtual ~ProgramImpl ()=default
 
void setData (const GrGLSLProgramDataManager &pdman, const GrFragmentProcessor &processor)
 
int numChildProcessors () const
 
ProgramImplchildProcessor (int index) const
 
void setFunctionName (SkString name)
 
const char * functionName () const
 
SkString invokeChild (int childIndex, EmitArgs &parentArgs, std::string_view skslCoords={})
 
SkString invokeChildWithMatrix (int childIndex, EmitArgs &parentArgs)
 
SkString invokeChild (int childIndex, const char *inputColor, EmitArgs &parentArgs, std::string_view skslCoords={})
 
SkString invokeChildWithMatrix (int childIndex, const char *inputColor, EmitArgs &parentArgs)
 
SkString invokeChild (int childIndex, const char *inputColor, const char *destColor, EmitArgs &parentArgs, std::string_view skslCoords={})
 
SkString invokeChildWithMatrix (int childIndex, const char *inputColor, const char *destColor, EmitArgs &parentArgs)
 

Private Member Functions

void onSetData (const GrGLSLProgramDataManager &, const GrFragmentProcessor &) override
 

Additional Inherited Members

- Public Types inherited from GrFragmentProcessor::ProgramImpl
using UniformHandle = GrGLSLUniformHandler::UniformHandle
 
using SamplerHandle = GrGLSLUniformHandler::SamplerHandle
 

Detailed Description

Definition at line 532 of file GrRRectEffect.cpp.

Member Function Documentation

◆ emitCode()

void EllipticalRRectEffect::Impl::emitCode ( EmitArgs args)
overridevirtual

Implements GrFragmentProcessor::ProgramImpl.

Definition at line 545 of file GrRRectEffect.cpp.

545 {
546 const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>();
547 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
548 const char *rectName;
549 // The inner rect is the rrect bounds inset by the x/y radii
550 fInnerRectUniform = uniformHandler->addUniform(&erre, kFragment_GrShaderFlag, SkSLType::kFloat4,
551 "innerRect", &rectName);
552
553 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
554 // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
555 // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
556 // to that corner. This means that points near the interior near the rrect top edge will have
557 // a vector that points straight up for both the TL left and TR corners. Computing an
558 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
559 // fragments near the other three edges will get the correct AA. Fragments in the interior of
560 // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will
561 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
562 //
563 // The code below is a simplified version of the above that performs maxs on the vector
564 // components before computing distances and alpha values so that only one distance computation
565 // need be computed to determine the min alpha.
566 fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName);
567 fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName);
568
569
570 const char* scaleName = nullptr;
571 if (elliptical_effect_uses_scale(*args.fShaderCaps, erre.fRRect)) {
572 fScaleUniform = uniformHandler->addUniform(&erre, kFragment_GrShaderFlag, SkSLType::kHalf2,
573 "scale", &scaleName);
574 }
575
576 // The uniforms with the inv squared radii are highp to prevent underflow.
577 switch (erre.fRRect.getType()) {
579 const char *invRadiiXYSqdName;
580 fInvRadiiSqdUniform = uniformHandler->addUniform(&erre,
583 "invRadiiXY",
584 &invRadiiXYSqdName);
585 fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);");
586 if (scaleName) {
587 fragBuilder->codeAppendf("dxy *= %s.y;", scaleName);
588 }
589 // Z is the x/y offsets divided by squared radii.
590 fragBuilder->codeAppendf("float2 Z = dxy * %s.xy;", invRadiiXYSqdName);
591 break;
592 }
594 const char *invRadiiLTRBSqdName;
595 fInvRadiiSqdUniform = uniformHandler->addUniform(&erre,
598 "invRadiiLTRB",
599 &invRadiiLTRBSqdName);
600 if (scaleName) {
601 fragBuilder->codeAppendf("dxy0 *= %s.y;", scaleName);
602 fragBuilder->codeAppendf("dxy1 *= %s.y;", scaleName);
603 }
604 fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);");
605 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
606 // corner where both the x and y offsets are positive, hence the maxes. (The inverse
607 // squared radii will always be positive.)
608 fragBuilder->codeAppendf("float2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);",
609 invRadiiLTRBSqdName, invRadiiLTRBSqdName);
610
611 break;
612 }
613 default:
614 SK_ABORT("RRect should always be simple or nine-patch.");
615 }
616 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
617 fragBuilder->codeAppend("half implicit = half(dot(Z, dxy) - 1.0);");
618 // grad_dot is the squared length of the gradient of the implicit.
619 fragBuilder->codeAppend("half grad_dot = half(4.0 * dot(Z, Z));");
620 // avoid calling inversesqrt on zero.
621 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
622 fragBuilder->codeAppend("half approx_dist = implicit * half(inversesqrt(grad_dot));");
623 if (scaleName) {
624 fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName);
625 }
626
627 if (erre.fEdgeType == GrClipEdgeType::kFillAA) {
628 fragBuilder->codeAppend("half alpha = clamp(0.5 - approx_dist, 0.0, 1.0);");
629 } else {
630 fragBuilder->codeAppend("half alpha = clamp(0.5 + approx_dist, 0.0, 1.0);");
631 }
632
633 SkString inputSample = this->invokeChild(/*childIndex=*/0, args);
634
635 fragBuilder->codeAppendf("return %s * alpha;", inputSample.c_str());
636}
static bool elliptical_effect_uses_scale(const GrShaderCaps &caps, const SkRRect &rrect)
@ kFragment_GrShaderFlag
#define SK_ABORT(message,...)
Definition SkAssert.h:70
SkString invokeChild(int childIndex, EmitArgs &parentArgs, std::string_view skslCoords={})
void codeAppend(const char *str)
void codeAppendf(const char format[],...) SK_PRINTF_LIKE(2
@ kSimple_Type
non-zero width and height with equal radii
Definition SkRRect.h:70
@ kNinePatch_Type
non-zero width and height with axis-aligned radii
Definition SkRRect.h:71
const char * c_str() const
Definition SkString.h:133
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args

◆ onSetData()

void EllipticalRRectEffect::Impl::onSetData ( const GrGLSLProgramDataManager ,
const GrFragmentProcessor  
)
overrideprivatevirtual

A ProgramImpl instance can be reused with any GrFragmentProcessor that produces the same the same key; this function reads data from a GrFragmentProcessor and uploads any uniform variables required by the shaders created in emitCode(). The GrFragmentProcessor parameter is guaranteed to be of the same type that created this ProgramImpl and to have an identical key as the one that created this ProgramImpl.

Reimplemented from GrFragmentProcessor::ProgramImpl.

Definition at line 638 of file GrRRectEffect.cpp.

639 {
640 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>();
641 const SkRRect& rrect = erre.fRRect;
642 // If we're using a scale factor to work around precision issues, choose the largest radius
643 // as the scale factor. The inv radii need to be pre-adjusted by the scale factor.
644 if (rrect != fPrevRRect) {
647 SkASSERT(r0.fX >= kRadiusMin);
648 SkASSERT(r0.fY >= kRadiusMin);
649 switch (rrect.getType()) {
651 rect.inset(r0.fX, r0.fY);
652 if (fScaleUniform.isValid()) {
653 if (r0.fX > r0.fY) {
654 pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY));
655 pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX);
656 } else {
657 pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f);
658 pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY);
659 }
660 } else {
661 pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
662 1.f / (r0.fY * r0.fY));
663 }
664 break;
667 SkASSERT(r1.fX >= kRadiusMin);
668 SkASSERT(r1.fY >= kRadiusMin);
669 rect.fLeft += r0.fX;
670 rect.fTop += r0.fY;
671 rect.fRight -= r1.fX;
672 rect.fBottom -= r1.fY;
673 if (fScaleUniform.isValid()) {
674 float scale = std::max(std::max(r0.fX, r0.fY), std::max(r1.fX, r1.fY));
675 float scaleSqd = scale * scale;
676 pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX),
677 scaleSqd / (r0.fY * r0.fY),
678 scaleSqd / (r1.fX * r1.fX),
679 scaleSqd / (r1.fY * r1.fY));
680 pdman.set2f(fScaleUniform, scale, 1.f / scale);
681 } else {
682 pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
683 1.f / (r0.fY * r0.fY),
684 1.f / (r1.fX * r1.fX),
685 1.f / (r1.fY * r1.fY));
686 }
687 break;
688 }
689 default:
690 SK_ABORT("RRect should always be simple or nine-patch.");
691 }
692 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
693 fPrevRRect = rrect;
694 }
695}
static const SkScalar kRadiusMin
#define SkASSERT(cond)
Definition SkAssert.h:116
Type getType() const
Definition SkRRect.h:76
SkVector radii(Corner corner) const
Definition SkRRect.h:271
@ kUpperLeft_Corner
index of top-left corner radii
Definition SkRRect.h:252
@ kLowerRight_Corner
index of bottom-right corner radii
Definition SkRRect.h:254
const SkRect & getBounds() const
Definition SkRRect.h:279
SkRRect rrect
Definition SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350
const Scalar scale
float fX
x-axis value
float fY
y-axis value

The documentation for this class was generated from the following file: