Convert internal sample() calls to shade/filter/blend
Bug: skia:12302 Change-Id: I8cf958acf9214d0de903a4097647afd74f2a659e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/441541 Reviewed-by: John Stiles <johnstiles@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
7b3edfa659
commit
293497e77f
@ -66,10 +66,10 @@
|
||||
}
|
||||
|
||||
half4 main(float2 p) {
|
||||
half4 pa = sample(image, float2(p.x-0.5, p.y-0.5));
|
||||
half4 pb = sample(image, float2(p.x+0.5, p.y-0.5));
|
||||
half4 pc = sample(image, float2(p.x-0.5, p.y+0.5));
|
||||
half4 pd = sample(image, float2(p.x+0.5, p.y+0.5));
|
||||
half4 pa = shade(image, float2(p.x-0.5, p.y-0.5));
|
||||
half4 pb = shade(image, float2(p.x+0.5, p.y-0.5));
|
||||
half4 pc = shade(image, float2(p.x-0.5, p.y+0.5));
|
||||
half4 pd = shade(image, float2(p.x+0.5, p.y+0.5));
|
||||
float2 w = sharpen(fract(p + 0.5));
|
||||
if (do_smooth > 0) {
|
||||
w = smooth(w);
|
||||
|
@ -64,10 +64,10 @@ function init() {
|
||||
float h = nearly_center(p) ? 0.0 : 0.5;
|
||||
|
||||
// Manual bilerp logic
|
||||
half4 pa = sample(image, float2(p.x-h, p.y-h));
|
||||
half4 pb = sample(image, float2(p.x+h, p.y-h));
|
||||
half4 pc = sample(image, float2(p.x-h, p.y+h));
|
||||
half4 pd = sample(image, float2(p.x+h, p.y+h));
|
||||
half4 pa = shade(image, float2(p.x-h, p.y-h));
|
||||
half4 pb = shade(image, float2(p.x+h, p.y-h));
|
||||
half4 pc = shade(image, float2(p.x-h, p.y+h));
|
||||
half4 pd = shade(image, float2(p.x+h, p.y+h));
|
||||
|
||||
// Now 'sharpen' the weighting. This is the magic sauce where we different
|
||||
// from a normal bilerp
|
||||
|
@ -38,20 +38,15 @@ bool FuzzSKSL2Pipeline(sk_sp<SkData> bytes) {
|
||||
void declareGlobal(const char* /*declaration*/) override {}
|
||||
|
||||
String sampleShader(int index, String coords) override {
|
||||
return "sample(" + SkSL::to_string(index) + ", " + coords + ")";
|
||||
return "shade(" + SkSL::to_string(index) + ", " + coords + ")";
|
||||
}
|
||||
|
||||
String sampleColorFilter(int index, String color) override {
|
||||
String result = "sample(" + SkSL::to_string(index);
|
||||
if (!color.empty()) {
|
||||
result += ", " + color;
|
||||
}
|
||||
result += ")";
|
||||
return result;
|
||||
return "filter(" + SkSL::to_string(index) + ", " + color + ")";
|
||||
}
|
||||
|
||||
String sampleBlender(int index, String src, String dst) override {
|
||||
return "sample(" + SkSL::to_string(index) + ", " + src + ", " + dst + ")";
|
||||
return "blend(" + SkSL::to_string(index) + ", " + src + ", " + dst + ")";
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -66,7 +66,7 @@ static sk_sp<SkColorFilter> MakeTintColorFilter(SkColor lo, SkColor hi, bool use
|
||||
auto [effect, error] = SkRuntimeEffect::MakeForColorFilter(SkString(R"(
|
||||
uniform colorFilter inner;
|
||||
uniform colorFilter outer;
|
||||
half4 main(half4 c) { return sample(outer, sample(inner, c)); }
|
||||
half4 main(half4 c) { return filter(outer, filter(inner, c)); }
|
||||
)"));
|
||||
SkASSERT(effect);
|
||||
SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
|
||||
|
@ -35,7 +35,7 @@ protected:
|
||||
half b = fract((p.x + 5)/10);
|
||||
half a = min(distance(p, vec2(50, 50))/50 + 0.3, 1);
|
||||
half4 result = half4(r, g, b, a);
|
||||
result *= sample(child, p);
|
||||
result *= shade(child, p);
|
||||
if (gAlphaType == 0) {
|
||||
result.rgb *= a;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ static sk_sp<SkImageFilter> make_filter() {
|
||||
uniform shader input;
|
||||
half4 main(float2 coord) {
|
||||
coord.x += sin(coord.y / 3) * 4;
|
||||
return sample(input, coord);
|
||||
return shade(input, coord);
|
||||
}
|
||||
)")).effect;
|
||||
return SkMakeRuntimeImageFilter(std::move(effect),
|
||||
|
@ -137,10 +137,10 @@ public:
|
||||
}
|
||||
|
||||
half4 main(float2 xy) {
|
||||
half4 before = sample(before_map, xy);
|
||||
half4 after = sample(after_map, xy);
|
||||
half4 before = shade(before_map, xy);
|
||||
half4 after = shade(after_map, xy);
|
||||
|
||||
float m = smooth_cutoff(sample(threshold_map, xy).a);
|
||||
float m = smooth_cutoff(shade(threshold_map, xy).a);
|
||||
return mix(before, after, m);
|
||||
}
|
||||
)", kAnimate_RTFlag | kBench_RTFlag) {}
|
||||
@ -228,11 +228,11 @@ public:
|
||||
UnsharpRT() : RuntimeShaderGM("unsharp_rt", {512, 256}, R"(
|
||||
uniform shader input;
|
||||
half4 main(float2 xy) {
|
||||
half4 c = sample(input, xy) * 5;
|
||||
c -= sample(input, xy + float2( 1, 0));
|
||||
c -= sample(input, xy + float2(-1, 0));
|
||||
c -= sample(input, xy + float2( 0, 1));
|
||||
c -= sample(input, xy + float2( 0, -1));
|
||||
half4 c = shade(input, xy) * 5;
|
||||
c -= shade(input, xy + float2( 1, 0));
|
||||
c -= shade(input, xy + float2(-1, 0));
|
||||
c -= shade(input, xy + float2( 0, 1));
|
||||
c -= shade(input, xy + float2( 0, -1));
|
||||
return c;
|
||||
}
|
||||
)") {}
|
||||
@ -273,7 +273,7 @@ public:
|
||||
uniform float inv_size;
|
||||
|
||||
half4 main(float2 xy) {
|
||||
float4 c = unpremul(sample(input, xy));
|
||||
float4 c = unpremul(shade(input, xy));
|
||||
|
||||
// Map to cube coords:
|
||||
float3 cubeCoords = float3(c.rg * rg_scale + rg_bias, c.b * b_scale);
|
||||
@ -283,7 +283,7 @@ public:
|
||||
float2 coords2 = float2(( ceil(cubeCoords.b) + cubeCoords.r) * inv_size, cubeCoords.g);
|
||||
|
||||
// Two bilinear fetches, plus a manual lerp for the third axis:
|
||||
half4 color = mix(sample(color_cube, coords1), sample(color_cube, coords2),
|
||||
half4 color = mix(shade(color_cube, coords1), shade(color_cube, coords2),
|
||||
fract(cubeCoords.b));
|
||||
|
||||
// Premul again
|
||||
@ -366,7 +366,7 @@ public:
|
||||
float2 coords2 = float2(( ceil(cubeCoords.b) + cubeCoords.r) * inv_size, cubeCoords.g);
|
||||
|
||||
// Two bilinear fetches, plus a manual lerp for the third axis:
|
||||
half4 color = mix(sample(color_cube, coords1), sample(color_cube, coords2),
|
||||
half4 color = mix(shade(color_cube, coords1), shade(color_cube, coords2),
|
||||
fract(cubeCoords.b));
|
||||
|
||||
// Premul again
|
||||
@ -429,7 +429,7 @@ public:
|
||||
DefaultColorRT() : RuntimeShaderGM("default_color_rt", {512, 256}, R"(
|
||||
uniform shader input;
|
||||
half4 main(float2 xy) {
|
||||
return sample(input, xy);
|
||||
return shade(input, xy);
|
||||
}
|
||||
)") {}
|
||||
|
||||
@ -624,7 +624,7 @@ DEF_SIMPLE_GM(child_sampling_rt, canvas, 256,256) {
|
||||
static constexpr char scale[] =
|
||||
"uniform shader child;"
|
||||
"half4 main(float2 xy) {"
|
||||
" return sample(child, xy*0.1);"
|
||||
" return shade(child, xy*0.1);"
|
||||
"}";
|
||||
|
||||
SkPaint p;
|
||||
|
@ -463,10 +463,10 @@
|
||||
}
|
||||
|
||||
half4 main(float2 xy) {
|
||||
half4 before = sample(before_map, xy);
|
||||
half4 after = sample(after_map, xy);
|
||||
half4 before = shade(before_map, xy);
|
||||
half4 after = shade(after_map, xy);
|
||||
|
||||
float m = smooth_cutoff(sample(threshold_map, xy).r);
|
||||
float m = smooth_cutoff(shade(threshold_map, xy).r);
|
||||
return mix(before, after, half(m));
|
||||
}`;
|
||||
|
||||
|
@ -117,10 +117,10 @@ float smooth_cutoff(float x) {
|
||||
}
|
||||
|
||||
half4 main(float2 xy) {
|
||||
half4 before = sample(before_map, xy);
|
||||
half4 after = sample(after_map, xy);
|
||||
half4 before = shade(before_map, xy);
|
||||
half4 after = shade(after_map, xy);
|
||||
|
||||
float m = smooth_cutoff(sample(threshold_map, xy).r);
|
||||
float m = smooth_cutoff(shade(threshold_map, xy).r);
|
||||
return mix(before, after, half(m));
|
||||
}`;
|
||||
|
||||
|
@ -48,11 +48,11 @@ static constexpr char gDisplacementSkSL[] = R"(
|
||||
uniform half4 selector_offset;
|
||||
|
||||
half4 main(float2 xy) {
|
||||
half4 d = sample(displ, xy);
|
||||
half4 d = shade(displ, xy);
|
||||
|
||||
d = selector_matrix*unpremul(d) + selector_offset;
|
||||
|
||||
return sample(child, xy + d.xy*d.zw);
|
||||
return shade(child, xy + d.xy*d.zw);
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -77,7 +77,7 @@ static constexpr char gSphereSkSL[] = R"(
|
||||
0.5 + kRPI * asin(RN.y)
|
||||
);
|
||||
|
||||
return apply_light(EYE, N, sample(child, UV*child_scale));
|
||||
return apply_light(EYE, N, shade(child, UV*child_scale));
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
uniform shader child;
|
||||
half4 main(float2 p) {
|
||||
return sample(child, p.yx);
|
||||
return shade(child, p.yx);
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ shader s3;
|
||||
in shader s4;
|
||||
|
||||
// Various places that shaders should not be allowed:
|
||||
half4 local() { shader s; return sample(s, xy); }
|
||||
half4 parameter(shader s) { return sample(s, xy); }
|
||||
half4 local() { shader s; return shade(s, xy); }
|
||||
half4 parameter(shader s) { return shade(s, xy); }
|
||||
shader returned() { return s1; }
|
||||
half4 constructed() { return sample(shader(s1), xy); }
|
||||
half4 expression(bool b) { return sample(b ? s1 : s2, xy); }
|
||||
half4 constructed() { return shade(shader(s1), xy); }
|
||||
half4 expression(bool b) { return shade(b ? s1 : s2, xy); }
|
||||
|
@ -389,7 +389,7 @@ public:
|
||||
}
|
||||
|
||||
half4 main(float2 p) {
|
||||
float3 norm = convert_normal_sample(sample(normal_map, p));
|
||||
float3 norm = convert_normal_sample(shade(normal_map, p));
|
||||
float3 plane_norm = normalize(localToWorldAdjInv * norm.xyz0).xyz;
|
||||
|
||||
float3 plane_pos = (localToWorld * p.xy01).xyz;
|
||||
@ -399,7 +399,7 @@ public:
|
||||
float dp = dot(plane_norm, light_dir);
|
||||
float scale = min(ambient + max(dp, 0), 1);
|
||||
|
||||
return sample(color_map, p) * scale.xxx1;
|
||||
return shade(color_map, p) * scale.xxx1;
|
||||
}
|
||||
)";
|
||||
auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(code));
|
||||
|
@ -559,7 +559,7 @@ half4 main(float2 p) {
|
||||
}
|
||||
|
||||
half4 main(float2 p) {
|
||||
float3 norm = convert_normal_sample(sample(normal_map, p));
|
||||
float3 norm = convert_normal_sample(shade(normal_map, p));
|
||||
float3 plane_norm = normalize(localToWorldAdjInv * float4(norm, 0)).xyz;
|
||||
|
||||
float3 plane_pos = (localToWorld * float4(p, 0, 1)).xyz;
|
||||
@ -569,7 +569,7 @@ half4 main(float2 p) {
|
||||
float dp = dot(plane_norm, light_dir);
|
||||
float scale = min(ambient + max(dp, 0), 1);
|
||||
|
||||
return sample(color_map, p) * half4(float4(scale, scale, scale, 1));
|
||||
return shade(color_map, p) * half4(float4(scale, scale, scale, 1));
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -850,7 +850,7 @@ static std::unique_ptr<GrFragmentProcessor> make_circle_blur(GrRecordingContext*
|
||||
// to rearrange to avoid passing large values to length() that would overflow.
|
||||
half2 vec = half2((sk_FragCoord.xy - circleData.xy) * circleData.w);
|
||||
half dist = length(vec) + (0.5 - circleData.z) * circleData.w;
|
||||
return inColor * sample(blurProfile, half2(dist, 0.5)).a;
|
||||
return inColor * shade(blurProfile, half2(dist, 0.5)).a;
|
||||
}
|
||||
)");
|
||||
|
||||
@ -994,8 +994,8 @@ static std::unique_ptr<GrFragmentProcessor> make_rect_blur(GrRecordingContext* c
|
||||
// computations align the left edge of the integral texture with the inset rect's
|
||||
// edge extending outward 6 * sigma from the inset rect.
|
||||
half2 xy = max(half2(rect.LT - pos), half2(pos - rect.RB));
|
||||
xCoverage = sample(integral, half2(xy.x, 0.5)).a;
|
||||
yCoverage = sample(integral, half2(xy.y, 0.5)).a;
|
||||
xCoverage = shade(integral, half2(xy.x, 0.5)).a;
|
||||
yCoverage = shade(integral, half2(xy.y, 0.5)).a;
|
||||
} else {
|
||||
// We just consider just the x direction here. In practice we compute x and y
|
||||
// separately and multiply them together.
|
||||
@ -1013,10 +1013,10 @@ static std::unique_ptr<GrFragmentProcessor> make_rect_blur(GrRecordingContext* c
|
||||
// Also, our rect uniform was pre-inset by 3 sigma from the actual rect being
|
||||
// blurred, also factored in.
|
||||
half4 rect = half4(half2(rect.LT - pos), half2(pos - rect.RB));
|
||||
xCoverage = 1 - sample(integral, half2(rect.L, 0.5)).a
|
||||
- sample(integral, half2(rect.R, 0.5)).a;
|
||||
yCoverage = 1 - sample(integral, half2(rect.T, 0.5)).a
|
||||
- sample(integral, half2(rect.B, 0.5)).a;
|
||||
xCoverage = 1 - shade(integral, half2(rect.L, 0.5)).a
|
||||
- shade(integral, half2(rect.R, 0.5)).a;
|
||||
yCoverage = 1 - shade(integral, half2(rect.T, 0.5)).a
|
||||
- shade(integral, half2(rect.B, 0.5)).a;
|
||||
}
|
||||
return inColor * xCoverage * yCoverage;
|
||||
}
|
||||
@ -1426,7 +1426,7 @@ static std::unique_ptr<GrFragmentProcessor> make_rrect_blur(GrRecordingContext*
|
||||
half2 proxyDims = half2(2.0 * edgeSize);
|
||||
half2 texCoord = translatedFragPosHalf / proxyDims;
|
||||
|
||||
return inColor * sample(ninePatchFP, texCoord).a;
|
||||
return inColor * shade(ninePatchFP, texCoord).a;
|
||||
}
|
||||
)");
|
||||
|
||||
|
@ -477,7 +477,7 @@ sk_sp<SkColorFilter> SkColorFilters::Lerp(float weight, sk_sp<SkColorFilter> cf0
|
||||
"uniform colorFilter cf1;"
|
||||
"uniform half weight;"
|
||||
"half4 main(half4 color) {"
|
||||
"return mix(sample(cf0, color), sample(cf1, color), weight);"
|
||||
"return mix(filter(cf0, color), filter(cf1, color), weight);"
|
||||
"}"
|
||||
);
|
||||
SkASSERT(effect);
|
||||
|
@ -557,18 +557,9 @@ std::unique_ptr<SkFilterColorProgram> SkFilterColorProgram::Make(const SkRuntime
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We allocate a uniform color for the input color, and one for each call to sample(). When we
|
||||
// encounter a sample call, we record the index of the child being sampled, as well as the color
|
||||
// being passed. In most cases, we can record enough information to perfectly re-create that
|
||||
// call when we're later running the program. (We support calls that pass the original input
|
||||
// color, an immediate color, or the results of a previous sample call). If the color is none
|
||||
// of those, we are unable to use this per-effect program, and callers will need to fall back
|
||||
// to another (slower) implementation.
|
||||
|
||||
// We also require that any children are *also* color filters (not shaders or blenders). In
|
||||
// theory we could detect the coords being passed to shader children, and replicate those calls,
|
||||
// but that's very complicated, and has diminishing returns. (eg, for table lookup color
|
||||
// filters).
|
||||
// We require that any children are color filters (not shaders or blenders). In theory, we could
|
||||
// detect the coords being passed to shader children, and replicate those calls, but that's very
|
||||
// complicated, and has diminishing returns. (eg, for table lookup color filters).
|
||||
if (!std::all_of(effect->fChildren.begin(),
|
||||
effect->fChildren.end(),
|
||||
[](const SkRuntimeEffect::Child& c) {
|
||||
@ -605,10 +596,13 @@ std::unique_ptr<SkFilterColorProgram> SkFilterColorProgram::Make(const SkRuntime
|
||||
ua.offset == ur.offset + 12;
|
||||
};
|
||||
|
||||
// We reserve a uniform color for each call to sample(). While processing the SkSL, we record
|
||||
// the index of the child being sampled, and the color being filtered (in a SampleCall struct).
|
||||
// We reserve a uniform color for each child invocation. While processing the SkSL, we record
|
||||
// the index of the child, and the color being filtered (in a SampleCall struct).
|
||||
// When we run this program later, we use the SampleCall to evaluate the correct child, and
|
||||
// populate these uniform values. These Uniform ids are loads from the *second* arg ptr.
|
||||
// If the color being passed is too complex for us to describe and re-create using SampleCall,
|
||||
// we are unable to use this per-effect program, and callers will need to fall back to another
|
||||
// (slower) implementation.
|
||||
skvm::Uniforms childColorUniforms{p.uniform(), 0};
|
||||
skvm::Color inputColor = p.uniformColor(/*placeholder*/ SkColors::kWhite, &childColorUniforms);
|
||||
std::vector<SkFilterColorProgram::SampleCall> sampleCalls;
|
||||
|
@ -119,10 +119,10 @@ public:
|
||||
private:
|
||||
struct SampleCall {
|
||||
enum class Kind {
|
||||
kInputColor, // eg sample(child) or sample(child, inputColor)
|
||||
kImmediate, // eg sample(child, half4(1))
|
||||
kPrevious, // eg sample(child1, sample(child2))
|
||||
kUniform, // eg uniform half4 color; ... sample(child, color)
|
||||
kInputColor, // eg filter(child, inputColor)
|
||||
kImmediate, // eg filter(child, half4(1))
|
||||
kPrevious, // eg filter(child1, filter(child2, ...))
|
||||
kUniform, // eg uniform half4 color; ... filter(child, color)
|
||||
};
|
||||
|
||||
int fChild;
|
||||
|
@ -145,7 +145,7 @@ static std::unique_ptr<GrFragmentProcessor> make_alpha_threshold_fp(
|
||||
uniform half outerThreshold;
|
||||
|
||||
half4 main(float2 xy, half4 color) {
|
||||
half4 mask_color = sample(maskFP, xy);
|
||||
half4 mask_color = shade(maskFP, xy);
|
||||
if (mask_color.a < 0.5) {
|
||||
if (color.a > outerThreshold) {
|
||||
half scale = outerThreshold / color.a;
|
||||
|
@ -315,8 +315,8 @@ std::unique_ptr<GrFragmentProcessor> make_arithmetic_fp(
|
||||
uniform half4 k;
|
||||
uniform half pmClamp;
|
||||
half4 main(float2 xy) {
|
||||
half4 src = sample(srcFP, xy);
|
||||
half4 dst = sample(dstFP, xy);
|
||||
half4 src = shade(srcFP, xy);
|
||||
half4 dst = shade(dstFP, xy);
|
||||
half4 color = saturate(k.x * src * dst +
|
||||
k.y * src +
|
||||
k.z * dst +
|
||||
|
@ -126,7 +126,7 @@ static std::unique_ptr<GrFragmentProcessor> make_magnifier_fp(
|
||||
weight = min(min(delta_squared.x, delta_squared.y), 1.0);
|
||||
}
|
||||
|
||||
return sample(src, mix(coord, zoom_coord, weight));
|
||||
return shade(src, mix(coord, zoom_coord, weight));
|
||||
}
|
||||
)");
|
||||
|
||||
|
@ -402,10 +402,10 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(
|
||||
return nullptr;
|
||||
}
|
||||
static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
|
||||
uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
|
||||
uniform colorFilter fp; // Declared as colorFilter so we can pass a color
|
||||
uniform half4 color;
|
||||
half4 main(half4 inColor) {
|
||||
return sample(fp, color);
|
||||
return filter(fp, color);
|
||||
}
|
||||
)");
|
||||
SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
|
||||
@ -421,9 +421,9 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(
|
||||
std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::UseDestColorAsInput(
|
||||
std::unique_ptr<GrFragmentProcessor> fp) {
|
||||
static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForBlender, R"(
|
||||
uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
|
||||
uniform colorFilter fp; // Declared as colorFilter so we can pass a color
|
||||
half4 main(half4 src, half4 dst) {
|
||||
return sample(fp, dst);
|
||||
return filter(fp, dst);
|
||||
}
|
||||
)");
|
||||
return GrSkSLFP::Make(effect, "UseDestColorAsInput", /*inputFP=*/nullptr,
|
||||
@ -438,9 +438,9 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputOpaqueAndPost
|
||||
return nullptr;
|
||||
}
|
||||
static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
|
||||
uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
|
||||
uniform colorFilter fp; // Declared as colorFilter so we can pass a color
|
||||
half4 main(half4 inColor) {
|
||||
return inColor.a * sample(fp, unpremul(inColor).rgb1);
|
||||
return inColor.a * filter(fp, unpremul(inColor).rgb1);
|
||||
}
|
||||
)");
|
||||
return GrSkSLFP::Make(effect,
|
||||
|
@ -611,10 +611,9 @@ public:
|
||||
* to the child's helper function). It is legal to pass nullptr as inputColor, since all
|
||||
* fragment processors are required to work without an input color.
|
||||
*
|
||||
* When skslCoords is empty, invokeChild corresponds to a call to "sample(child, color)"
|
||||
* in SkSL. When skslCoords is not empty, invokeChild corresponds to a call to
|
||||
* "sample(child, color, float2)", where skslCoords is an SkSL expression that evaluates to a
|
||||
* float2 and is passed in as the 3rd argument.
|
||||
* When skslCoords is empty, the child is invoked at the sample coordinates from parentArgs.
|
||||
* When skslCoords is not empty, is must be an SkSL expression that evaluates to a float2.
|
||||
* That expression is passed to the child's processor function as the "_coords" argument.
|
||||
*/
|
||||
SkString invokeChild(int childIndex,
|
||||
const char* inputColor,
|
||||
|
@ -394,7 +394,7 @@ static std::unique_ptr<GrFragmentProcessor> make_dither_effect(
|
||||
uniform half range;
|
||||
uniform shader table;
|
||||
half4 main(float2 xy, half4 color) {
|
||||
half value = sample(table, sk_FragCoord.xy).a - 0.5; // undo the bias in the table
|
||||
half value = shade(table, sk_FragCoord.xy).a - 0.5; // undo the bias in the table
|
||||
// For each color channel, add the random offset to the channel value and then clamp
|
||||
// between 0 and alpha to keep the color premultiplied.
|
||||
return half4(clamp(color.rgb + value * range, 0.0, color.a), color.a);
|
||||
|
@ -425,7 +425,7 @@ static std::unique_ptr<GrFragmentProcessor> make_clamped_gradient(
|
||||
uniform int layoutPreservesOpacity; // specialized
|
||||
|
||||
half4 main(float2 coord) {
|
||||
half4 t = sample(gradLayout, coord);
|
||||
half4 t = shade(gradLayout, coord);
|
||||
half4 outColor;
|
||||
|
||||
// If t.x is below 0, use the left border color without invoking the child processor.
|
||||
@ -442,7 +442,7 @@ static std::unique_ptr<GrFragmentProcessor> make_clamped_gradient(
|
||||
} else {
|
||||
// Always sample from (x, 0), discarding y, since the layout FP can use y as a
|
||||
// side-channel.
|
||||
outColor = sample(colorizer, t.x0);
|
||||
outColor = shade(colorizer, t.x0);
|
||||
}
|
||||
if (bool(makePremul)) {
|
||||
outColor.rgb *= outColor.a;
|
||||
@ -487,7 +487,7 @@ static std::unique_ptr<GrFragmentProcessor> make_tiled_gradient(
|
||||
uniform int useFloorAbsWorkaround; // specialized
|
||||
|
||||
half4 main(float2 coord) {
|
||||
half4 t = sample(gradLayout, coord);
|
||||
half4 t = shade(gradLayout, coord);
|
||||
|
||||
if (!bool(layoutPreservesOpacity) && t.y < 0) {
|
||||
// layout has rejected this fragment (rely on sksl to remove this branch if the
|
||||
@ -511,7 +511,7 @@ static std::unique_ptr<GrFragmentProcessor> make_tiled_gradient(
|
||||
|
||||
// Always sample from (x, 0), discarding y, since the layout FP can use y as a
|
||||
// side-channel.
|
||||
half4 outColor = sample(colorizer, t.x0);
|
||||
half4 outColor = shade(colorizer, t.x0);
|
||||
if (bool(makePremul)) {
|
||||
outColor.rgb *= outColor.a;
|
||||
}
|
||||
|
@ -569,10 +569,10 @@ public:
|
||||
// Analysis
|
||||
|
||||
SampleUsage Analysis::GetSampleUsage(const Program& program,
|
||||
const Variable& fp,
|
||||
const Variable& child,
|
||||
bool writesToSampleCoords,
|
||||
int* elidedSampleCoordCount) {
|
||||
MergeSampleUsageVisitor visitor(*program.fContext, fp, writesToSampleCoords);
|
||||
MergeSampleUsageVisitor visitor(*program.fContext, child, writesToSampleCoords);
|
||||
SampleUsage result = visitor.visit(program);
|
||||
if (elidedSampleCoordCount) {
|
||||
*elidedSampleCoordCount += visitor.elidedSampleCoordCount();
|
||||
|
@ -35,14 +35,14 @@ enum class VariableRefKind : int8_t;
|
||||
*/
|
||||
struct Analysis {
|
||||
/**
|
||||
* Determines how `program` samples `fp`. By default, assumes that the sample coords
|
||||
* (SK_MAIN_COORDS_BUILTIN) might be modified, so `sample(fp, sampleCoords)` is treated as
|
||||
* Determines how `program` samples `child`. By default, assumes that the sample coords
|
||||
* (SK_MAIN_COORDS_BUILTIN) might be modified, so `shade(fp, sampleCoords)` is treated as
|
||||
* Explicit. If writesToSampleCoords is false, treats that as PassThrough, instead.
|
||||
* If elidedSampleCoordCount is provided, the pointed to value will be incremented by the
|
||||
* number of sample calls where the above rewrite was performed.
|
||||
*/
|
||||
static SampleUsage GetSampleUsage(const Program& program,
|
||||
const Variable& fp,
|
||||
const Variable& child,
|
||||
bool writesToSampleCoords = true,
|
||||
int* elidedSampleCoordCount = nullptr);
|
||||
|
||||
|
@ -428,20 +428,15 @@ ResultCode processCommand(std::vector<SkSL::String>& args) {
|
||||
}
|
||||
|
||||
String sampleShader(int index, String coords) override {
|
||||
return "sample(child_" + SkSL::to_string(index) + ", " + coords + ")";
|
||||
return "shade(child_" + SkSL::to_string(index) + ", " + coords + ")";
|
||||
}
|
||||
|
||||
String sampleColorFilter(int index, String color) override {
|
||||
String result = "sample(child_" + SkSL::to_string(index);
|
||||
if (!color.empty()) {
|
||||
result += ", " + color;
|
||||
}
|
||||
result += ")";
|
||||
return result;
|
||||
return "filter(child_" + SkSL::to_string(index) + ", " + color + ")";
|
||||
}
|
||||
|
||||
String sampleBlender(int index, String src, String dst) override {
|
||||
return "sample(child_" + SkSL::to_string(index) + ", " + src + ", " +
|
||||
return "blend(child_" + SkSL::to_string(index) + ", " + src + ", " +
|
||||
dst + ")";
|
||||
}
|
||||
|
||||
|
@ -459,7 +459,7 @@ static void test_RuntimeEffect_Shaders(skiatest::Reporter* r, GrRecordingContext
|
||||
|
||||
// Sampling a null child should return the paint color
|
||||
effect.build("uniform shader child;"
|
||||
"half4 main(float2 p) { return sample(child, p); }");
|
||||
"half4 main(float2 p) { return shade(child, p); }");
|
||||
effect.child("child") = nullptr;
|
||||
effect.test(0xFF00FFFF,
|
||||
[](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); });
|
||||
@ -468,13 +468,13 @@ static void test_RuntimeEffect_Shaders(skiatest::Reporter* r, GrRecordingContext
|
||||
|
||||
// Sampling a simple child at our coordinates
|
||||
effect.build("uniform shader child;"
|
||||
"half4 main(float2 p) { return sample(child, p); }");
|
||||
"half4 main(float2 p) { return shade(child, p); }");
|
||||
effect.child("child") = rgbwShader;
|
||||
effect.test({0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF});
|
||||
|
||||
// Sampling with explicit coordinates (reflecting about the diagonal)
|
||||
effect.build("uniform shader child;"
|
||||
"half4 main(float2 p) { return sample(child, p.yx); }");
|
||||
"half4 main(float2 p) { return shade(child, p.yx); }");
|
||||
effect.child("child") = rgbwShader;
|
||||
effect.test({0xFF0000FF, 0xFFFF0000, 0xFF00FF00, 0xFFFFFFFF});
|
||||
|
||||
@ -560,13 +560,13 @@ static void test_RuntimeEffect_Blenders(skiatest::Reporter* r, GrRecordingContex
|
||||
|
||||
// Sampling a null shader/color filter should return the paint color.
|
||||
effect.build("uniform shader child;"
|
||||
"half4 main(half4 s, half4 d) { return sample(child, s.rg); }");
|
||||
"half4 main(half4 s, half4 d) { return shade(child, s.rg); }");
|
||||
effect.child("child") = nullptr;
|
||||
effect.test(0xFF00FFFF,
|
||||
[](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); });
|
||||
|
||||
effect.build("uniform colorFilter child;"
|
||||
"half4 main(half4 s, half4 d) { return sample(child, s); }");
|
||||
"half4 main(half4 s, half4 d) { return filter(child, s); }");
|
||||
effect.child("child") = nullptr;
|
||||
effect.test(0xFF00FFFF,
|
||||
[](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); });
|
||||
@ -574,7 +574,7 @@ static void test_RuntimeEffect_Blenders(skiatest::Reporter* r, GrRecordingContex
|
||||
// Sampling a null blender should do a src-over blend. Draw 50% black over RGBW to verify this.
|
||||
surface->getCanvas()->drawPaint(rgbwPaint);
|
||||
effect.build("uniform blender child;"
|
||||
"half4 main(half4 s, half4 d) { return sample(child, s, d); }");
|
||||
"half4 main(half4 s, half4 d) { return blend(child, s, d); }");
|
||||
effect.child("child") = nullptr;
|
||||
effect.test({0xFF000080, 0xFF008000, 0xFF800000, 0xFF808080},
|
||||
[](SkCanvas*, SkPaint* paint) { paint->setColor4f({0.0f, 0.0f, 0.0f, 0.497f}); });
|
||||
@ -582,7 +582,7 @@ static void test_RuntimeEffect_Blenders(skiatest::Reporter* r, GrRecordingContex
|
||||
// Sampling a shader at various coordinates
|
||||
effect.build("uniform shader child;"
|
||||
"uniform half2 pos;"
|
||||
"half4 main(half4 s, half4 d) { return sample(child, pos); }");
|
||||
"half4 main(half4 s, half4 d) { return shade(child, pos); }");
|
||||
effect.child("child") = make_RGBW_shader();
|
||||
effect.uniform("pos") = float2{0, 0};
|
||||
effect.test(0xFF0000FF);
|
||||
@ -598,14 +598,14 @@ static void test_RuntimeEffect_Blenders(skiatest::Reporter* r, GrRecordingContex
|
||||
|
||||
// Sampling a color filter
|
||||
effect.build("uniform colorFilter child;"
|
||||
"half4 main(half4 s, half4 d) { return sample(child, half4(1)); }");
|
||||
"half4 main(half4 s, half4 d) { return filter(child, half4(1)); }");
|
||||
effect.child("child") = SkColorFilters::Blend(0xFF012345, SkBlendMode::kSrc);
|
||||
effect.test(0xFF452301);
|
||||
|
||||
// Sampling a built-in blender
|
||||
surface->getCanvas()->drawPaint(rgbwPaint);
|
||||
effect.build("uniform blender child;"
|
||||
"half4 main(half4 s, half4 d) { return sample(child, s, d); }");
|
||||
"half4 main(half4 s, half4 d) { return blend(child, s, d); }");
|
||||
effect.child("child") = SkBlender::Mode(SkBlendMode::kPlus);
|
||||
effect.test({0xFF4523FF, 0xFF45FF01, 0xFFFF2301, 0xFFFFFFFF},
|
||||
[](SkCanvas*, SkPaint* paint) { paint->setColor(0xFF012345); });
|
||||
@ -613,7 +613,7 @@ static void test_RuntimeEffect_Blenders(skiatest::Reporter* r, GrRecordingContex
|
||||
// Sampling a runtime-effect blender
|
||||
surface->getCanvas()->drawPaint(rgbwPaint);
|
||||
effect.build("uniform blender child;"
|
||||
"half4 main(half4 s, half4 d) { return sample(child, s, d); }");
|
||||
"half4 main(half4 s, half4 d) { return blend(child, s, d); }");
|
||||
effect.child("child") = SkBlenders::Arithmetic(0, 1, 1, 0, /*enforcePremul=*/false);
|
||||
effect.test({0xFF4523FF, 0xFF45FF01, 0xFFFF2301, 0xFFFFFFFF},
|
||||
[](SkCanvas*, SkPaint* paint) { paint->setColor(0xFF012345); });
|
||||
@ -736,7 +736,7 @@ static void test_RuntimeEffectStructNameReuse(skiatest::Reporter* r, GrRecording
|
||||
"uniform shader paint;"
|
||||
"struct S { half4 rgba; };"
|
||||
"void process(inout S s) { s.rgba.rgb *= 0.5; }"
|
||||
"half4 main(float2 p) { S s; s.rgba = sample(paint, p); process(s); return s.rgba; }"
|
||||
"half4 main(float2 p) { S s; s.rgba = shade(paint, p); process(s); return s.rgba; }"
|
||||
));
|
||||
REPORTER_ASSERT(r, childEffect, "%s\n", err.c_str());
|
||||
sk_sp<SkShader> nullChild = nullptr;
|
||||
@ -755,7 +755,7 @@ static void test_RuntimeEffectStructNameReuse(skiatest::Reporter* r, GrRecording
|
||||
"uniform shader child;"
|
||||
"struct S { float2 coord; };"
|
||||
"void process(inout S s) { s.coord = s.coord.yx; }"
|
||||
"half4 main(float2 p) { S s; s.coord = p; process(s); return sample(child, s.coord); "
|
||||
"half4 main(float2 p) { S s; s.coord = p; process(s); return shade(child, s.coord); "
|
||||
"}");
|
||||
effect.child("child") = child;
|
||||
effect.test(0xFF00407F, [](SkCanvas*, SkPaint* paint) {
|
||||
@ -815,31 +815,31 @@ DEF_TEST(SkRuntimeShaderSampleCoords, r) {
|
||||
|
||||
// Direct use of passed-in coords. Here, the only use of sample coords is for a sample call
|
||||
// converted to passthrough, so referenceSampleCoords is *false*, despite appearing in main.
|
||||
test("half4 main(float2 xy) { return sample(child, xy); }", false, false);
|
||||
test("half4 main(float2 xy) { return shade(child, xy); }", false, false);
|
||||
// Sample with passed-in coords, read (but don't write) sample coords elsewhere
|
||||
test("half4 main(float2 xy) { return sample(child, xy) + sin(xy.x); }", false, true);
|
||||
test("half4 main(float2 xy) { return shade(child, xy) + sin(xy.x); }", false, true);
|
||||
|
||||
// Cases where our optimization is not valid, and does not happen:
|
||||
|
||||
// Sampling with values completely unrelated to passed-in coords
|
||||
test("half4 main(float2 xy) { return sample(child, float2(0, 0)); }", true, false);
|
||||
test("half4 main(float2 xy) { return shade(child, float2(0, 0)); }", true, false);
|
||||
// Use of expression involving passed in coords
|
||||
test("half4 main(float2 xy) { return sample(child, xy * 0.5); }", true, true);
|
||||
test("half4 main(float2 xy) { return shade(child, xy * 0.5); }", true, true);
|
||||
// Use of coords after modification
|
||||
test("half4 main(float2 xy) { xy *= 2; return sample(child, xy); }", true, true);
|
||||
test("half4 main(float2 xy) { xy *= 2; return shade(child, xy); }", true, true);
|
||||
// Use of coords after modification via out-param call
|
||||
test("void adjust(inout float2 xy) { xy *= 2; }"
|
||||
"half4 main(float2 xy) { adjust(xy); return sample(child, xy); }", true, true);
|
||||
"half4 main(float2 xy) { adjust(xy); return shade(child, xy); }", true, true);
|
||||
|
||||
// There should (must) not be any false-positive cases. There are false-negatives.
|
||||
// In all of these cases, our optimization would be valid, but does not happen:
|
||||
|
||||
// Direct use of passed-in coords, modified after use
|
||||
test("half4 main(float2 xy) { half4 c = sample(child, xy); xy *= 2; return c; }", true, true);
|
||||
test("half4 main(float2 xy) { half4 c = shade(child, xy); xy *= 2; return c; }", true, true);
|
||||
// Passed-in coords copied to a temp variable
|
||||
test("half4 main(float2 xy) { float2 p = xy; return sample(child, p); }", true, true);
|
||||
test("half4 main(float2 xy) { float2 p = xy; return shade(child, p); }", true, true);
|
||||
// Use of coords passed to helper function
|
||||
test("half4 helper(float2 xy) { return sample(child, xy); }"
|
||||
test("half4 helper(float2 xy) { return shade(child, xy); }"
|
||||
"half4 main(float2 xy) { return helper(xy); }", true, true);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
half4 main(float2 p)
|
||||
{
|
||||
return half4(sample(child_0, _coords.yx));
|
||||
return half4(shade(child_0, _coords.yx));
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ sk_sp<SkBlender> GetRuntimeBlendForBlendMode(SkBlendMode mode) {
|
||||
static auto result = SkRuntimeEffect::MakeForBlender(SkString(R"(
|
||||
uniform blender b;
|
||||
half4 main(half4 src, half4 dst) {
|
||||
return sample(b, src, dst);
|
||||
return blend(b, src, dst);
|
||||
}
|
||||
)"));
|
||||
|
||||
|
@ -43,7 +43,7 @@ SkSLSlide::SkSLSlide() {
|
||||
"uniform shader child;\n"
|
||||
"\n"
|
||||
"half4 main(float2 p) {\n"
|
||||
" return sample(child, p);\n"
|
||||
" return shade(child, p);\n"
|
||||
"}\n";
|
||||
|
||||
fCodeIsDirty = true;
|
||||
|
Loading…
Reference in New Issue
Block a user