Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Macros | Typedefs
GrFragmentProcessor.cpp File Reference
#include "src/gpu/ganesh/GrFragmentProcessor.h"
#include "include/core/SkM44.h"
#include "src/base/SkVx.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/gpu/KeyBuilder.h"
#include "src/gpu/ganesh/GrPipeline.h"
#include "src/gpu/ganesh/GrProcessorAnalysis.h"
#include "src/gpu/ganesh/GrShaderCaps.h"
#include "src/gpu/ganesh/effects/GrBlendFragmentProcessor.h"
#include "src/gpu/ganesh/effects/GrSkSLFP.h"
#include "src/gpu/ganesh/effects/GrTextureEffect.h"
#include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/ganesh/glsl/GrGLSLProgramBuilder.h"
#include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
#include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"

Go to the source code of this file.

Macros

#define CLIP_EDGE_SKSL
 

Typedefs

using ProgramImpl = GrFragmentProcessor::ProgramImpl
 

Macro Definition Documentation

◆ CLIP_EDGE_SKSL

#define CLIP_EDGE_SKSL
Value:
"const int kFillBW = 0;" \
"const int kFillAA = 1;" \
"const int kInverseFillBW = 2;" \
"const int kInverseFillAA = 3;"

Definition at line 593 of file GrFragmentProcessor.cpp.

604 {
607 "uniform int edgeType;" // GrClipEdgeType, specialized
608 "uniform float4 rectUniform;"
609
610 "half4 main(float2 xy) {"
611 "half coverage;"
612 "if (edgeType == kFillBW || edgeType == kInverseFillBW) {"
613 // non-AA
614 "coverage = half(all(greaterThan(float4(sk_FragCoord.xy, rectUniform.zw),"
615 "float4(rectUniform.xy, sk_FragCoord.xy))));"
616 "} else {"
617 // compute coverage relative to left and right edges, add, then subtract 1 to
618 // account for double counting. And similar for top/bottom.
619 "half4 dists4 = saturate(half4(1, 1, -1, -1) *"
620 "half4(sk_FragCoord.xyxy - rectUniform));"
621 "half2 dists2 = dists4.xy + dists4.zw - 1;"
622 "coverage = dists2.x * dists2.y;"
623 "}"
624
625 "if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {"
626 "coverage = 1.0 - coverage;"
627 "}"
628
629 "return half4(coverage);"
630 "}"
631 );
632
633 SkASSERT(rect.isSorted());
634 // The AA math in the shader evaluates to 0 at the uploaded coordinates, so outset by 0.5
635 // to interpolate from 0 at a half pixel inset and 1 at a half pixel outset of rect.
636 SkRect rectUniform = GrClipEdgeTypeIsAA(edgeType) ? rect.makeOutset(.5f, .5f) : rect;
637
638 auto rectFP = GrSkSLFP::Make(effect, "Rect", /*inputFP=*/nullptr,
640 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
641 "rectUniform", rectUniform);
642 return GrBlendFragmentProcessor::Make<SkBlendMode::kModulate>(std::move(rectFP),
643 std::move(inputFP));
644}
645
646GrFPResult GrFragmentProcessor::Circle(std::unique_ptr<GrFragmentProcessor> inputFP,
647 GrClipEdgeType edgeType,
649 float radius) {
650 // A radius below half causes the implicit insetting done by this processor to become
651 // inverted. We could handle this case by making the processor code more complicated.
652 if (radius < .5f && GrClipEdgeTypeIsInverseFill(edgeType)) {
653 return GrFPFailure(std::move(inputFP));
654 }
655
658 "uniform int edgeType;" // GrClipEdgeType, specialized
659 // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
660 // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
661 "uniform float4 circle;"
662
663 "half4 main(float2 xy) {"
664 // TODO: Right now the distance to circle calculation is performed in a space normalized
665 // to the radius and then denormalized. This is to mitigate overflow on devices that
666 // don't have full float.
667 "half d;"
668 "if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {"
669 "d = half((length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z);"
670 "} else {"
671 "d = half((1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z);"
672 "}"
673 "return half4((edgeType == kFillAA || edgeType == kInverseFillAA)"
674 "? saturate(d)"
675 ": (d > 0.5 ? 1 : 0));"
676 "}"
677 );
678
679 SkScalar effectiveRadius = radius;
680 if (GrClipEdgeTypeIsInverseFill(edgeType)) {
681 effectiveRadius -= 0.5f;
682 // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
683 effectiveRadius = std::max(0.001f, effectiveRadius);
684 } else {
685 effectiveRadius += 0.5f;
686 }
687 SkV4 circle = {center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius)};
688
689 auto circleFP = GrSkSLFP::Make(effect, "Circle", /*inputFP=*/nullptr,
691 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
692 "circle", circle);
693 return GrFPSuccess(GrBlendFragmentProcessor::Make<SkBlendMode::kModulate>(std::move(inputFP),
694 std::move(circleFP)));
695}
696
697GrFPResult GrFragmentProcessor::Ellipse(std::unique_ptr<GrFragmentProcessor> inputFP,
698 GrClipEdgeType edgeType,
700 SkPoint radii,
701 const GrShaderCaps& caps) {
702 const bool medPrecision = !caps.fFloatIs32Bits;
703
704 // Small radii produce bad results on devices without full float.
705 if (medPrecision && (radii.fX < 0.5f || radii.fY < 0.5f)) {
706 return GrFPFailure(std::move(inputFP));
707 }
708 // Very narrow ellipses produce bad results on devices without full float
709 if (medPrecision && (radii.fX > 255*radii.fY || radii.fY > 255*radii.fX)) {
710 return GrFPFailure(std::move(inputFP));
711 }
712 // Very large ellipses produce bad results on devices without full float
713 if (medPrecision && (radii.fX > 16384 || radii.fY > 16384)) {
714 return GrFPFailure(std::move(inputFP));
715 }
716
719 "uniform int edgeType;" // GrClipEdgeType, specialized
720 "uniform int medPrecision;" // !sk_Caps.floatIs32Bits, specialized
721
722 "uniform float4 ellipse;"
723 "uniform float2 scale;" // only for medPrecision
724
725 "half4 main(float2 xy) {"
726 // d is the offset to the ellipse center
727 "float2 d = sk_FragCoord.xy - ellipse.xy;"
728 // If we're on a device with a "real" mediump then we'll do the distance computation in
729 // a space that is normalized by the larger radius or 128, whichever is smaller. The
730 // scale uniform will be scale, 1/scale. The inverse squared radii uniform values are
731 // already in this normalized space. The center is not.
732 "if (bool(medPrecision)) {"
733 "d *= scale.y;"
734 "}"
735 "float2 Z = d * ellipse.zw;"
736 // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
737 "float implicit = dot(Z, d) - 1;"
738 // grad_dot is the squared length of the gradient of the implicit.
739 "float grad_dot = 4 * dot(Z, Z);"
740 // Avoid calling inversesqrt on zero.
741 "if (bool(medPrecision)) {"
742 "grad_dot = max(grad_dot, 6.1036e-5);"
743 "} else {"
744 "grad_dot = max(grad_dot, 1.1755e-38);"
745 "}"
746 "float approx_dist = implicit * inversesqrt(grad_dot);"
747 "if (bool(medPrecision)) {"
748 "approx_dist *= scale.x;"
749 "}"
750
751 "half alpha;"
752 "if (edgeType == kFillBW) {"
753 "alpha = approx_dist > 0.0 ? 0.0 : 1.0;"
754 "} else if (edgeType == kFillAA) {"
755 "alpha = saturate(0.5 - half(approx_dist));"
756 "} else if (edgeType == kInverseFillBW) {"
757 "alpha = approx_dist > 0.0 ? 1.0 : 0.0;"
758 "} else {" // edgeType == kInverseFillAA
759 "alpha = saturate(0.5 + half(approx_dist));"
760 "}"
761 "return half4(alpha);"
762 "}"
763 );
764
765 float invRXSqd;
766 float invRYSqd;
767 SkV2 scale = {1, 1};
768 // If we're using a scale factor to work around precision issues, choose the larger radius as
769 // the scale factor. The inv radii need to be pre-adjusted by the scale factor.
770 if (medPrecision) {
771 if (radii.fX > radii.fY) {
772 invRXSqd = 1.f;
773 invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
774 scale = {radii.fX, 1.f / radii.fX};
775 } else {
776 invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
777 invRYSqd = 1.f;
778 scale = {radii.fY, 1.f / radii.fY};
779 }
780 } else {
781 invRXSqd = 1.f / (radii.fX * radii.fX);
782 invRYSqd = 1.f / (radii.fY * radii.fY);
783 }
784 SkV4 ellipse = {center.fX, center.fY, invRXSqd, invRYSqd};
785
786 auto ellipseFP = GrSkSLFP::Make(effect, "Ellipse", /*inputFP=*/nullptr,
788 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
789 "medPrecision", GrSkSLFP::Specialize<int>(medPrecision),
790 "ellipse", ellipse,
791 "scale", scale);
792 return GrFPSuccess(GrBlendFragmentProcessor::Make<SkBlendMode::kModulate>(std::move(ellipseFP),
793 std::move(inputFP)));
794}
795
796//////////////////////////////////////////////////////////////////////////////
797
798std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::HighPrecision(
799 std::unique_ptr<GrFragmentProcessor> fp) {
800 class HighPrecisionFragmentProcessor : public GrFragmentProcessor {
801 public:
802 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
803 return std::unique_ptr<GrFragmentProcessor>(
804 new HighPrecisionFragmentProcessor(std::move(fp)));
805 }
806
807 const char* name() const override { return "HighPrecision"; }
808
809 std::unique_ptr<GrFragmentProcessor> clone() const override {
810 return Make(this->childProcessor(0)->clone());
811 }
812
813 private:
814 HighPrecisionFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp)
815 : INHERITED(kHighPrecisionFragmentProcessor_ClassID,
816 ProcessorOptimizationFlags(fp.get())) {
817 this->registerChild(std::move(fp));
818 }
819
820 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
821 class Impl : public ProgramImpl {
822 public:
823 void emitCode(EmitArgs& args) override {
824 SkString childColor = this->invokeChild(0, args);
825
826 args.fFragBuilder->forceHighPrecision();
827 args.fFragBuilder->codeAppendf("return %s;", childColor.c_str());
828 }
829 };
830 return std::make_unique<Impl>();
831 }
832
833 void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override {}
834 bool onIsEqual(const GrFragmentProcessor& other) const override { return true; }
835
836 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
837 return ConstantOutputForConstantInput(this->childProcessor(0), input);
838 }
839
841 };
842
843 return HighPrecisionFragmentProcessor::Make(std::move(fp));
844}
845
846//////////////////////////////////////////////////////////////////////////////
847
849
851 const GrFragmentProcessor& processor) {
852 this->onSetData(pdman, processor);
853}
854
856 const char* inputColor,
857 const char* destColor,
858 EmitArgs& args,
859 std::string_view skslCoords) {
860 SkASSERT(childIndex >= 0);
861
862 if (!inputColor) {
863 inputColor = args.fInputColor;
864 }
865
866 const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
867 if (!childProc) {
868 // If no child processor is provided, return the input color as-is.
869 return SkString(inputColor);
870 }
871
872 auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
873 inputColor);
874
875 if (childProc->isBlendFunction()) {
876 if (!destColor) {
877 destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
878 }
879 invocation.appendf(", %s", destColor);
880 }
881
882 // Assert that the child has no sample matrix. A uniform matrix sample call would go through
883 // invokeChildWithMatrix, not here.
884 SkASSERT(!childProc->sampleUsage().isUniformMatrix());
885
886 if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
887 SkASSERT(!childProc->sampleUsage().isFragCoord() || skslCoords == "sk_FragCoord.xy");
888 // The child's function takes a half4 color and a float2 coordinate
889 if (!skslCoords.empty()) {
890 invocation.appendf(", %.*s", (int)skslCoords.size(), skslCoords.data());
891 } else {
892 invocation.appendf(", %s", args.fSampleCoord);
893 }
894 }
895
896 invocation.append(")");
897 return invocation;
898}
899
901 const char* inputColor,
902 const char* destColor,
903 EmitArgs& args) {
904 SkASSERT(childIndex >= 0);
905
906 if (!inputColor) {
907 inputColor = args.fInputColor;
908 }
909
910 const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
911 if (!childProc) {
912 // If no child processor is provided, return the input color as-is.
913 return SkString(inputColor);
914 }
915
916 SkASSERT(childProc->sampleUsage().isUniformMatrix());
917
918 // Every uniform matrix has the same (initial) name. Resolve that into the mangled name:
919 GrShaderVar uniform = args.fUniformHandler->getUniformMapping(
922 const SkString& matrixName(uniform.getName());
923
924 auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
925 inputColor);
926
927 if (childProc->isBlendFunction()) {
928 if (!destColor) {
929 destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
930 }
931 invocation.appendf(", %s", destColor);
932 }
933
934 // Produce a string containing the call to the helper function. We have a uniform variable
935 // containing our transform (matrixName). If the parent coords were produced by uniform
936 // transforms, then the entire expression (matrixName * coords) is lifted to a vertex shader
937 // and is stored in a varying. In that case, childProc will not be sampled explicitly, so its
938 // function signature will not take in coords.
939 //
940 // In all other cases, we need to insert sksl to compute matrix * parent coords and then invoke
941 // the function.
942 if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
943 // Only check perspective for this specific matrix transform, not the aggregate FP property.
944 // Any parent perspective will have already been applied when evaluated in the FS.
945 if (childProc->sampleUsage().hasPerspective()) {
946 invocation.appendf(", proj((%s) * %s.xy1)", matrixName.c_str(), args.fSampleCoord);
947 } else if (args.fShaderCaps->fNonsquareMatrixSupport) {
948 invocation.appendf(", float3x2(%s) * %s.xy1", matrixName.c_str(), args.fSampleCoord);
949 } else {
950 invocation.appendf(", ((%s) * %s.xy1).xy", matrixName.c_str(), args.fSampleCoord);
951 }
952 }
953
954 invocation.append(")");
955 return invocation;
956}
#define CLIP_EDGE_SKSL
static GrFPResult GrFPSuccess(std::unique_ptr< GrFragmentProcessor > fp)
std::tuple< bool, std::unique_ptr< GrFragmentProcessor > > GrFPResult
static GrFPResult GrFPFailure(std::unique_ptr< GrFragmentProcessor > fp)
static constexpr bool GrClipEdgeTypeIsInverseFill(const GrClipEdgeType edgeType)
GrClipEdgeType
static constexpr bool GrClipEdgeTypeIsAA(const GrClipEdgeType edgeType)
#define SkASSERT(cond)
Definition SkAssert.h:116
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
#define INHERITED(method,...)
SkRuntimeEffect * SkMakeRuntimeEffect(SkRuntimeEffect::Result(*make)(SkString, const SkRuntimeEffect::Options &), const char *sksl, SkRuntimeEffect::Options options=SkRuntimeEffect::Options{})
#define SkScalarInvert(x)
Definition SkScalar.h:73
SK_API SkString static SkString SkStringPrintf()
Definition SkString.h:287
static SkScalar center(float pos0, float pos1)
SkString invokeChildWithMatrix(int childIndex, EmitArgs &parentArgs)
void setData(const GrGLSLProgramDataManager &pdman, const GrFragmentProcessor &processor)
virtual void onSetData(const GrGLSLProgramDataManager &, const GrFragmentProcessor &)
SkString invokeChild(int childIndex, EmitArgs &parentArgs, std::string_view skslCoords={})
ProgramImpl * childProcessor(int index) const
static GrFPResult Circle(std::unique_ptr< GrFragmentProcessor >, GrClipEdgeType, SkPoint center, float radius)
GrFragmentProcessor * childProcessor(int index)
const SkSL::SampleUsage & sampleUsage() const
static std::unique_ptr< GrFragmentProcessor > HighPrecision(std::unique_ptr< GrFragmentProcessor >)
static GrFPResult Ellipse(std::unique_ptr< GrFragmentProcessor >, GrClipEdgeType, SkPoint center, SkPoint radii, const GrShaderCaps &)
SkSLType getType() const
Definition GrShaderVar.h:97
const SkString & getName() const
Definition GrShaderVar.h:91
static std::unique_ptr< GrSkSLFP > Make(const SkRuntimeEffect *effect, const char *name, std::unique_ptr< GrFragmentProcessor > inputFP, OptFlags optFlags, Args &&... args)
Definition GrSkSLFP.h:158
static GrSpecializedUniform< T > Specialize(const T &value)
Definition GrSkSLFP.h:76
static Result MakeForShader(SkString sksl, const Options &)
bool isUniformMatrix() const
static const char * MatrixUniformName()
bool isFragCoord() const
bool hasPerspective() const
const char * c_str() const
Definition SkString.h:133
float SkScalar
Definition extension.cpp:12
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const char * name
Definition fuchsia.cc:50
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350
const uint32_t fp
const myers::Point & get(const myers::Segment &)
const Scalar scale
float fX
x-axis value
float fY
y-axis value
Definition SkM44.h:19
Definition SkM44.h:98

Typedef Documentation

◆ ProgramImpl

Definition at line 849 of file GrFragmentProcessor.cpp.