61#include <initializer_list>
73#if defined(SK_GRAPHITE)
95 "Expected error message to contain \"%s\". Actual message: \"%s\"",
96 expected, errorText.c_str());
99#define EMPTY_MAIN "half4 main(float2 p) { return half4(0); }"
109DEF_TEST(SkRuntimeEffectInvalid_UndefinedFunction, r) {
111 "function 'half4 missing()' is not defined");
119DEF_TEST(SkRuntimeEffectInvalid_SkCapsDisallowed, r) {
123 "half4 main(float2 p) { return sk_Caps.floatIs32Bits ? half4(1) : half4(0); }",
124 "name 'sk_Caps' is reserved");
127DEF_TEST(SkRuntimeEffect_DeadCodeEliminationStackOverflow, r) {
130 half4 main(half4 color) {
131 half value = color.r;
133 for (int a=0; a<10; ++a) { // 10
134 for (int b=0; b<10; ++b) { // 100
135 for (int c=0; c<10; ++c) { // 1000
136 for (int d=0; d<10; ++d) { // 10000
146DEF_TEST(SkRuntimeEffectCanDisableES2Restrictions, r) {
154 test_valid_es3 (r,
"float f[2] = float[2](0, 1);" EMPTY_MAIN);
164 "construction of array type");
165 test_valid (r,
"#version 300\nfloat f[2] = float[2](0, 1);" EMPTY_MAIN);
170 uniform int simple; // should have no flags
171 uniform float arrayOfOne[1]; // should have kArray_Flag
172 uniform float arrayOfMultiple[2]; // should have kArray_Flag
173 layout(color) uniform float4 color; // should have kColor_Flag
174 uniform half3 halfPrecisionFloat; // should have kHalfPrecision_Flag
175 layout(color) uniform half4 allFlags[2]; // should have Array | Color | HalfPrecision
206 auto test_valid = [r](
const char* sksl) {
211 auto test_invalid = [r](
const char* sksl,
const char* expected) {
215 errorText.contains(expected),
216 "Expected error message to contain \"%s\". Actual message: \"%s\"",
222 test_valid(
"half4 main(half4 c) { return c; }");
223 test_valid(
"float4 main(half4 c) { return c; }");
224 test_valid(
"half4 main(float4 c) { return c; }");
225 test_valid(
"float4 main(float4 c) { return c; }");
226 test_valid(
"vec4 main(half4 c) { return c; }");
227 test_valid(
"half4 main(vec4 c) { return c; }");
228 test_valid(
"vec4 main(vec4 c) { return c; }");
231 test_invalid(
"void main(half4 c) {}",
"'main' must return");
232 test_invalid(
"half3 main(half4 c) { return c.rgb; }",
"'main' must return");
235 test_invalid(
"half4 main() { return half4(1); }",
"'main' parameter");
236 test_invalid(
"half4 main(float2 p) { return half4(1); }",
"'main' parameter");
237 test_invalid(
"half4 main(float2 p, half4 c) { return c; }",
"'main' parameter");
240 test_invalid(
"half4 main(half4 c) { return sk_FragCoord.xy01; }",
"unknown identifier");
243 test_valid(
"uniform shader child;"
244 "half4 main(half4 c) { return child.eval(c.rg); }");
247 test_valid(
"uniform colorFilter child;"
248 "half4 main(half4 c) { return child.eval(c); }");
251 test_valid(
"uniform blender child;"
252 "half4 main(half4 c) { return child.eval(c, c); }");
257 auto test_valid = [r](
const char* sksl) {
262 auto test_invalid = [r](
const char* sksl,
const char* expected) {
266 errorText.contains(expected),
267 "Expected error message to contain \"%s\". Actual message: \"%s\"",
274 test_valid(
"half4 main(half4 s, half4 d) { return s; }");
275 test_valid(
"float4 main(float4 s, float4 d) { return d; }");
276 test_valid(
"float4 main(half4 s, float4 d) { return s; }");
277 test_valid(
"half4 main(float4 s, half4 d) { return d; }");
278 test_valid(
"vec4 main(half4 s, half4 d) { return s; }");
279 test_valid(
"half4 main(vec4 s, vec4 d) { return d; }");
280 test_valid(
"vec4 main(vec4 s, vec4 d) { return s; }");
283 test_invalid(
"void main(half4 s, half4 d) {}",
"'main' must return");
284 test_invalid(
"half3 main(half4 s, half4 d) { return s.rgb; }",
"'main' must return");
287 test_invalid(
"half4 main() { return half4(1); }",
"'main' parameter");
288 test_invalid(
"half4 main(half4 c) { return c; }",
"'main' parameter");
289 test_invalid(
"half4 main(float2 p) { return half4(1); }",
"'main' parameter");
290 test_invalid(
"half4 main(float2 p, half4 c) { return c; }",
"'main' parameter");
291 test_invalid(
"half4 main(float2 p, half4 a, half4 b) { return a; }",
"'main' parameter");
292 test_invalid(
"half4 main(half4 a, half4 b, half4 c) { return a; }",
"'main' parameter");
295 test_invalid(
"half4 main(half4 s, half4 d) { return sk_FragCoord.xy01; }",
296 "unknown identifier");
299 test_valid(
"uniform shader child;"
300 "half4 main(half4 s, half4 d) { return child.eval(s.rg); }");
303 test_valid(
"uniform colorFilter child;"
304 "half4 main(half4 s, half4 d) { return child.eval(d); }");
307 test_valid(
"uniform blender child;"
308 "half4 main(half4 s, half4 d) { return child.eval(s, d); }");
319 const char* expected,
324 errorText.contains(expected),
325 "Expected error message to contain \"%s\". Actual message: \"%s\"",
332 test_valid(
"half4 main(float2 p) { return p.xyxy; }");
333 test_valid(
"float4 main(float2 p) { return p.xyxy; }");
334 test_valid(
"vec4 main(float2 p) { return p.xyxy; }");
335 test_valid(
"half4 main(vec2 p) { return p.xyxy; }");
336 test_valid(
"vec4 main(vec2 p) { return p.xyxy; }");
342 test_invalid(
"half4 main(float2 p, half4 c) { return c; }",
"'main' parameter");
345 test_invalid(
"half4 main(float2 p, float4 c) { return c; }",
"'main' parameter");
348 test_invalid(
"half4 main(float2 p, vec4 c) { return c; }",
"'main' parameter");
351 test_invalid(
"float4 main(float2 p, half4 c) { return c; }",
"'main' parameter");
354 test_invalid(
"vec4 main(float2 p, half4 c) { return c; }",
"'main' parameter");
357 test_invalid(
"vec4 main(vec2 p, vec4 c) { return c; }",
"'main' parameter");
361 test_invalid(
"void main(float2 p) {}",
"'main' must return");
362 test_invalid(
"half3 main(float2 p) { return p.xy1; }",
"'main' must return");
365 test_invalid(
"half4 main() { return half4(1); }",
"'main' parameter");
366 test_invalid(
"half4 main(half4 c) { return c; }",
"'main' parameter");
369 test_invalid(
"half4 main(float2 p) { return sk_FragCoord.xy01; }",
370 "unknown identifier 'sk_FragCoord'");
372 test_valid(
"half4 main(float2 p) { return sk_FragCoord.xy01; }",
options);
375 test_valid(
"uniform shader child;"
376 "half4 main(float2 p) { return child.eval(p); }");
379 test_valid(
"uniform colorFilter child;"
380 "half4 main(float2 p) { return child.eval(half4(1)); }");
383 test_valid(
"uniform blender child;"
384 "half4 main(float2 p) { return child.eval(half4(0.5), half4(0.6)); }");
391 if (preTestCallback) {
392 preTestCallback(canvas,
paint);
402 return surface->readPixels(dest, 0, 0);
408 std::array<GrColor, 4> expected) {
409 std::array<GrColor, 4> actual;
416 if (actual != expected) {
419 "Expected: [ %08x %08x %08x %08x ]\n"
420 "Got : [ %08x %08x %08x %08x ]\n"
422 expected[0], expected[1], expected[2], expected[3],
423 actual[0], actual[1], actual[2], actual[3],
424 effect->
source().c_str()));
434#if defined(SK_GRAPHITE)
437 }
else if (grContext) {
452 : fReporter(r), fGrContext(grContext), fGraphite(graphite), fSize(size) {
461 ERRORF(fReporter,
"Effect didn't compile: %s", errorText.c_str());
464 fBuilder.
init(std::move(effect));
475 void test(std::array<GrColor, 4> expected,
PreTestFn preTestCallback =
nullptr) {
478 ERRORF(fReporter,
"Effect didn't produce a shader");
492 paint.setShader(std::move(shader));
503 ERRORF(fReporter,
"Effect didn't produce a shader");
511 paint.setShader(std::move(debugShader));
517 debugTrace->dump(&wstream);
519 return std::string(
static_cast<const char*
>(streamData->data()), streamData->size());
523 this->
test({expected, expected, expected, expected}, preTestCallback);
538 : fReporter(r), fGrContext(grContext), fGraphite(graphite) {
545 ERRORF(fReporter,
"Effect didn't compile: %s", errorText.c_str());
548 fBuilder.
init(std::move(effect));
552 return fSurface.
get();
563 void test(std::array<GrColor, 4> expected,
PreTestFn preTestCallback =
nullptr) {
566 ERRORF(fReporter,
"Effect didn't produce a blender");
572 paint.setBlender(std::move(blender));
581 this->
test({expected, expected, expected, expected}, preTestCallback);
600 static constexpr SkScalar pos[] = { 0, .25f, .25f, .50f, .50f, .75, .75, 1 };
601 static_assert(std::size(colors) == std::size(
pos),
"size mismatch");
609 using float4 = std::array<float, 4>;
610 using int4 = std::array<int, 4>;
613 effect.
build(
"half4 main(float2 p) { return half4(half2(p - 0.5), 0, 1); }");
614 effect.
test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
617 effect.
build(
"uniform float4 gColor; half4 main(float2 p) { return half4(gColor); }");
618 effect.
uniform(
"gColor") =
float4{ 0.0f, 0.25f, 0.75f, 1.0f };
619 effect.
test(0xFFBF4000);
620 effect.
uniform(
"gColor") =
float4{ 1.0f, 0.0f, 0.0f, 0.498f };
621 effect.
test(0x7F0000FF);
624 effect.
build(
"uniform int4 gColor; half4 main(float2 p) { return half4(gColor) / 255.0; }");
625 effect.
uniform(
"gColor") = int4{ 0x00, 0x40, 0xBF, 0xFF };
626 effect.
test(0xFFBF4000);
627 effect.
uniform(
"gColor") = int4{ 0xFF, 0x00, 0x00, 0x7F };
628 effect.
test(0x7F0000FF);
634 "half4 main(float2 p) { return half4(0.498 * (half2(sk_FragCoord.xy) - 0.5), 0, 1); }");
635 effect.
test({0xFF000000, 0xFF00007F, 0xFF007F00, 0xFF007F7F},
639 effect.
build(
"half4 main(float2 p) { return float4(p - 0.5, 0, 1); }");
640 effect.
test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
643 effect.
build(
"float4 main(float2 p) { return float4(p - 0.5, 0, 1); }");
644 effect.
test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
645 effect.
build(
"vec4 main(float2 p) { return float4(p - 0.5, 0, 1); }");
646 effect.
test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
649 effect.
build(
"vec4 main(vec2 p) { p -= 0.5; return vec4(p, 0, 1); }");
650 effect.
test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
651 effect.
build(
"void moveCoords(inout vec2 p) { p -= 0.5; }"
652 "vec4 main(vec2 p) { moveCoords(p); return vec4(p, 0, 1); }");
653 effect.
test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
662 effect.
build(
"uniform shader child;"
663 "half4 main(float2 p) { return child.eval(p); }");
664 effect.
child(
"child") =
nullptr;
665 effect.
test(0x00000000,
670 effect.
build(
"uniform colorFilter child;"
671 "half4 main(float2 p) { return child.eval(half4(1, 1, 0, 1)); }");
672 effect.
child(
"child") =
nullptr;
673 effect.
test(0xFF00FFFF);
676 effect.
build(
"uniform blender child;"
677 "half4 main(float2 p) {"
678 " float4 src = float4(p - 0.5, 0, 1) * 0.498;"
679 " return child.eval(src, half4(0, 0, 0, 1));"
681 effect.
child(
"child") =
nullptr;
682 effect.
test({0xFF000000, 0xFF00007F, 0xFF007F00, 0xFF007F7F});
687 effect.
build(
"uniform shader child;"
688 "half4 main(float2 p) { return child.eval(p); }");
689 effect.
child(
"child") = rgbwShader;
690 effect.
test({0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF});
693 effect.
build(
"uniform shader child;"
694 "half4 main(float2 p) { return child.eval(p.yx); }");
695 effect.
child(
"child") = rgbwShader;
696 effect.
test({0xFF0000FF, 0xFFFF0000, 0xFF00FF00, 0xFFFFFFFF});
700 effect.
build(
"uniform shader child;"
701 "half4 main(float2 p) { return half4(0, 1, 0, 1); }");
702 effect.
child(
"child") = rgbwShader;
703 effect.
test(0xFF00FF00);
710 effect.
build(
"float2 helper(float2 x) { return x + 1; }"
711 "half4 main(float2 p) { float2 v = helper(p); return half4(half2(v), 0, 1); }");
712 effect.
test(0xFF00FFFF);
719#if defined(SK_GRAPHITE)
722 std::unique_ptr<skgpu::graphite::Recorder> recorder = context->makeRecorder();
772 half4 main(float2 xy) { return half4(0, 1, 0, 1); }
776 paint.setShader(effect->makeShader(nullptr, {}));
788 half4 main(float2 xy) {
789 half4 result = half4(0, 1, 0, 1);
790 result.g = intBitsToFloat(floatBitsToInt(result.g));
796 paint.setShader(effect->makeShader(nullptr, {}));
808 half4 main(half4 src, half4 dst) { return half4(0, 1, 0, 1); }
812 paint.setBlender(effect->makeBlender(nullptr, {}));
820 half4 main(half4 src, half4 dst) {
821 half4 result = half4(0, 1, 0, 1);
822 result.g = intBitsToFloat(floatBitsToInt(result.g));
828 paint.setBlender(effect->makeBlender(nullptr, {}));
862 half4 main(half4 color) { return half4(2); }
866 paint.setColorFilter(effect->makeColorFilter(nullptr));
878 half4 main(half4 inColor) { return half4(1, 0, 0, 1); }
887 half4 main(half4 inColor) {
888 half4 result = half4(1, 0, 0, 1);
889 for (int i = 0; i < loops; i++) {
890 result = result.argb;
900 for (
int imageSize : {2, 80}) {
902 SkISize{imageSize, imageSize});
904 half4 main(float2 p) {
905 float2 val = p - 0.5;
909 int center = imageSize / 2;
911 static constexpr char kSkRPSlotDump[] =
912R
"($0 = p (float2 : slot 1/2, L0)
913$1 = p (float2 : slot 2/2, L0)
914$2 = [main].result (float4 : slot 1/4, L0)
915$3 = [main].result (float4 : slot 2/4, L0)
916$4 = [main].result (float4 : slot 3/4, L0)
917$5 = [main].result (float4 : slot 4/4, L0)
918$6 = val (float2 : slot 1/2, L0)
919$7 = val (float2 : slot 2/2, L0)
920F0 = half4 main(float2 p)
923enter half4 main(float2 p)
936exit half4 main(float2 p)
941 "Trace does not match expectation for %dx%d:\n%.*s\n",
942 imageSize, imageSize, (
int)
dump.size(),
dump.data());
946DEF_TEST(SkRuntimeEffectTracesAreUnoptimized, r) {
950 int globalUnreferencedVar = 7;
951 half inlinableFunction() {
954 half4 main(float2 p) {
956 int localUnreferencedVar = 7;
958 return inlinableFunction().xxxx;
961 std::string dump = effect.trace({1, 1});
962 static constexpr char kSkRPSlotDump[] =
963R
"($0 = p (float2 : slot 1/2, L0)
964$1 = p (float2 : slot 2/2, L0)
965$2 = globalUnreferencedVar (int, L0)
966$3 = [main].result (float4 : slot 1/4, L0)
967$4 = [main].result (float4 : slot 2/4, L0)
968$5 = [main].result (float4 : slot 3/4, L0)
969$6 = [main].result (float4 : slot 4/4, L0)
970$7 = localUnreferencedVar (int, L0)
971$8 = [inlinableFunction].result (float, L0)
972F0 = half4 main(float2 p)
973F1 = half inlinableFunction()
975 static constexpr char kExpectedTrace[] = R
"(
976globalUnreferencedVar = 7
977enter half4 main(float2 p)
984 localUnreferencedVar = 7
987 enter half inlinableFunction()
990 [inlinableFunction].result = 1
992 exit half inlinableFunction()
998exit half4 main(float2 p)
1003 "Trace output does not match expectation:\n%.*s\n", (
int)
dump.size(),
dump.data());
1006DEF_TEST(SkRuntimeEffectTraceCodeThatCannotBeUnoptimized, r) {
1010 half4 main(float2 p) {
1011 int variableThatGetsOptimizedAway = 7;
1015 // This (unreachable) path doesn't return a value.
1016 // Without optimization, SkSL thinks this code doesn't return a value on every path.
1019 std::string dump = effect.trace({1, 1});
1020 static constexpr char kSkRPSlotDump[] =
1021R
"($0 = p (float2 : slot 1/2, L0)
1022$1 = p (float2 : slot 2/2, L0)
1023$2 = [main].result (float4 : slot 1/4, L0)
1024$3 = [main].result (float4 : slot 2/4, L0)
1025$4 = [main].result (float4 : slot 3/4, L0)
1026$5 = [main].result (float4 : slot 4/4, L0)
1027F0 = half4 main(float2 p)
1029 static constexpr char kExpectedTrace[] = R
"(
1030enter half4 main(float2 p)
1042exit half4 main(float2 p)
1047 "Trace output does not match expectation:\n%.*s\n", (
int)
dump.size(),
dump.data());
1053 TestBlend effect(r, grContext, graphite);
1055 using float2 = std::array<float, 2>;
1056 using float4 = std::array<float, 4>;
1057 using int4 = std::array<int, 4>;
1060 effect.build(
"uniform float4 gColor; half4 main(half4 s, half4 d) { return half4(gColor); }");
1061 effect.uniform(
"gColor") =
float4{ 0.0f, 0.25f, 0.75f, 1.0f };
1062 effect.test(0xFFBF4000);
1063 effect.uniform(
"gColor") =
float4{ 1.0f, 0.0f, 0.0f, 0.498f };
1064 effect.test(0x7F0000FF);
1067 effect.build(
"uniform int4 gColor;"
1068 "half4 main(half4 s, half4 d) { return half4(gColor) / 255.0; }");
1069 effect.uniform(
"gColor") =
int4{ 0x00, 0x40, 0xBF, 0xFF };
1070 effect.test(0xFFBF4000);
1071 effect.uniform(
"gColor") =
int4{ 0xFF, 0x00, 0x00, 0x7F };
1072 effect.test(0x7F0000FF);
1075 effect.build(
"half4 main(half4 s, half4 d) { s += d; d += s; return half4(1); }");
1076 effect.test(0xFFFFFFFF);
1080 effect.build(
"half4 main(half4 s, half4 d) { return s; }");
1081 effect.test(0xFF888888);
1087 effect.surface()->getCanvas()->drawPaint(rgbwPaint);
1091 effect.build(
"half4 main(half4 s, half4 d) { return d; }");
1092 effect.test({0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF});
1096 effect.build(
"half4 main(half4 s, half4 d) { return half4(1) - d; }");
1097 effect.test({0x00FFFF00, 0x00FF00FF, 0x0000FFFF, 0x00000000});
1100 effect.build(
"half4 main(half4 s, half4 d) { return half4(-1); }");
1101 effect.test(0x00000000);
1102 effect.build(
"half4 main(half4 s, half4 d) { return half4(2); }");
1103 effect.test(0xFFFFFFFF);
1110 effect.build(
"uniform shader child;"
1111 "half4 main(half4 s, half4 d) { return child.eval(s.rg); }");
1112 effect.child(
"child") =
nullptr;
1113 effect.test(0x00000000,
1116 effect.build(
"uniform colorFilter child;"
1117 "half4 main(half4 s, half4 d) { return child.eval(s); }");
1118 effect.child(
"child") =
nullptr;
1119 effect.test(0xFF00FFFF,
1123 effect.surface()->getCanvas()->drawPaint(rgbwPaint);
1124 effect.build(
"uniform blender child;"
1125 "half4 main(half4 s, half4 d) { return child.eval(s, d); }");
1126 effect.child(
"child") =
nullptr;
1127 effect.test({0xFF000080, 0xFF008000, 0xFF800000, 0xFF808080},
1131 effect.build(
"uniform shader child;"
1132 "uniform half2 pos;"
1133 "half4 main(half4 s, half4 d) { return child.eval(pos); }");
1135 effect.uniform(
"pos") =
float2{0.5, 0.5};
1136 effect.test(0xFF0000FF);
1138 effect.uniform(
"pos") =
float2{1.5, 0.5};
1139 effect.test(0xFF00FF00);
1141 effect.uniform(
"pos") =
float2{0.5, 1.5};
1142 effect.test(0xFFFF0000);
1144 effect.uniform(
"pos") =
float2{1.5, 1.5};
1145 effect.test(0xFFFFFFFF);
1148 effect.build(
"uniform colorFilter child;"
1149 "half4 main(half4 s, half4 d) { return child.eval(half4(1)); }");
1151 effect.test(0xFF452301);
1154 effect.surface()->getCanvas()->drawPaint(rgbwPaint);
1155 effect.build(
"uniform blender child;"
1156 "half4 main(half4 s, half4 d) { return child.eval(s, d); }");
1158 effect.test({0xFF4523FF, 0xFF45FF01, 0xFFFF2301, 0xFFFFFFFF},
1162 effect.surface()->getCanvas()->drawPaint(rgbwPaint);
1163 effect.build(
"uniform blender child;"
1164 "half4 main(half4 s, half4 d) { return child.eval(s, d); }");
1166 effect.test({0xFF4523FF, 0xFF45FF01, 0xFFFF2301, 0xFFFFFFFF},
1170DEF_TEST(SkRuntimeEffect_Blender_CPU, r) {
1181DEF_TEST(SkRuntimeShaderBuilderReuse, r) {
1184 half4 main(float2 p) { return half4(x); }
1192 b.uniform(
"x") = 0.0f;
1193 auto shader_0 =
b.makeShader();
1195 b.uniform(
"x") = 1.0f;
1196 auto shader_1 =
b.makeShader();
1199DEF_TEST(SkRuntimeBlendBuilderReuse, r) {
1202 half4 main(half4 s, half4 d) { return half4(x); }
1210 for (
float x = 0.0f;
x <= 2.0f;
x += 2.0f) {
1216DEF_TEST(SkRuntimeShaderBuilderSetUniforms, r) {
1217 const char* kSource = R
"(
1219 uniform vec2 offset;
1220 half4 main(float2 p) { return half4(x); }
1233 float origin[] = { 2.0f, 3.0f, 4.0f };
1241 auto shader =
b.makeShader();
1244DEF_TEST(SkRuntimeEffectThreaded, r) {
1248 static constexpr char kSource[] =
"half4 main(float2 p) { return sk_FragCoord.xyxy; }";
1250 std::thread threads[16];
1251 for (
auto& thread : threads) {
1252 thread = std::thread([r]() {
1260 for (
auto& thread : threads) {
1265DEF_TEST(SkRuntimeEffectAllowsPrivateAccess, r) {
1272 static constexpr char kShader[] =
1273 "half4 main(float2 p) { return $hsl_to_rgb(p.xxx, p.y); }";
1285 "half4 main(half4 c) { return $hsl_to_rgb(c.rgb, c.a); }";
1296 static constexpr char kBlender[] =
1297 "half4 main(half4 s, half4 d) { return $hsl_to_rgb(s.rgb, d.a); }";
1307DEF_TEST(SkRuntimeColorFilterSingleColor, r) {
1309 auto [effect, err] =
1317 SkColor4f c = cf->filterColor4f({0.25, 0.5, 0.75, 1.0},
1328 "uniform shader paint;"
1329 "struct S { half4 rgba; };"
1330 "void process(inout S s) { s.rgba.rgb *= 0.5; }"
1331 "half4 main(float2 p) { S s; s.rgba = paint.eval(p); process(s); return s.rgba; }"
1334 sk_sp<SkShader> sourceColor = SkShaders::Color({0.99608f, 0.50196f, 0.0f, 1.0f},
nullptr);
1342 "uniform shader child;"
1343 "struct S { float2 coord; };"
1344 "void process(inout S s) { s.coord = s.coord.yx; }"
1345 "half4 main(float2 p) { S s; s.coord = p; process(s); return child.eval(s.coord); "
1347 effect.child(
"child") = child;
1351DEF_TEST(SkRuntimeStructNameReuse, r) {
1362DEF_TEST(SkRuntimeColorFilterFlags, r) {
1363 auto expectAlphaUnchanged = [&](
const char* shader) {
1367 REPORTER_ASSERT(r, filter && filter->isAlphaUnchanged(),
"%s", shader);
1370 auto expectAlphaChanged = [&](
const char* shader) {
1374 REPORTER_ASSERT(r, filter && !filter->isAlphaUnchanged(),
"%s", shader);
1378 expectAlphaUnchanged(
"half4 main(half4 color) { return color; }");
1379 expectAlphaUnchanged(
"half4 main(half4 color) { return color.aaaa; }");
1380 expectAlphaUnchanged(
"half4 main(half4 color) { return color.bgra; }");
1381 expectAlphaUnchanged(
"half4 main(half4 color) { return color.rraa; }");
1382 expectAlphaUnchanged(
"half4 main(half4 color) { return color.010a; }");
1383 expectAlphaUnchanged(
"half4 main(half4 color) { return half4(0, 0, 0, color.a); }");
1384 expectAlphaUnchanged(
"half4 main(half4 color) { return half4(half2(1), color.ba); }");
1385 expectAlphaUnchanged(
"half4 main(half4 color) { return half4(half2(1), half2(color.a)); }");
1386 expectAlphaUnchanged(
"half4 main(half4 color) { return half4(color.a); }");
1387 expectAlphaUnchanged(
"half4 main(half4 color) { return half4(float4(color.baba)); }");
1388 expectAlphaUnchanged(
"half4 main(half4 color) { return color.r != color.g ? color :"
1390 expectAlphaUnchanged(
"half4 main(half4 color) { return color.a == color.r ? color.rrra : "
1391 "color.g == color.b ? color.ggga : "
1394 expectAlphaChanged(
"half4 main(half4 color) { color.a = 0; return color; }");
1397 expectAlphaChanged(
"half4 main(half4 color) { return color.argb; }");
1398 expectAlphaChanged(
"half4 main(half4 color) { return color.rrrr; }");
1401 expectAlphaChanged(
"half4 main(half4 color) { return half4(1, 1, 1, color.r); }");
1404 expectAlphaChanged(
"half4 main(half4 color) { return half4(color.r); }");
1407 expectAlphaChanged(
"half4 main(half4 color) { return color.a > 0 ? half4(0) : color; }");
1408 expectAlphaChanged(
"half4 main(half4 color) { return color.g < 1 ? color.bgra : color.abgr; }");
1409 expectAlphaChanged(
"half4 main(half4 color) { return color.b > 0.5 ? half4(0) : half4(1); }");
1413 expectAlphaChanged(
"half4 main(half4 color) { return color + half4(1,1,1,0); }");
1414 expectAlphaChanged(
"half4 main(half4 color) { return color + half4(0,0,0,4); }");
1417 expectAlphaChanged(
"half4 main(half4 color) { "
1418 " if (color.r > 0.5) { return color; }"
1421 expectAlphaChanged(
"half4 main(half4 color) { "
1422 " if (color.r > 0.5) { return half4(0); }"
1427DEF_TEST(SkRuntimeShaderSampleCoords, r) {
1435 auto test = [&](
const char*
src,
bool expectExplicit,
bool expectReferencesSampleCoords) {
1436 auto [effect, err] =
1445 REPORTER_ASSERT(r,
fp->childProcessor(0)->sampleUsage().isExplicit() == expectExplicit);
1453 test(
"half4 main(float2 xy) { return child.eval(xy); }",
false,
false);
1455 test(
"half4 main(float2 xy) { return child.eval(xy) + sin(xy.x); }",
false,
true);
1460 test(
"half4 main(float2 xy) { return child.eval(float2(0, 0)); }",
true,
false);
1462 test(
"half4 main(float2 xy) { return child.eval(xy * 0.5); }",
true,
true);
1464 test(
"half4 main(float2 xy) { xy *= 2; return child.eval(xy); }",
true,
true);
1466 test(
"void adjust(inout float2 xy) { xy *= 2; }"
1467 "half4 main(float2 xy) { adjust(xy); return child.eval(xy); }",
true,
true);
1473 test(
"half4 main(float2 xy) { half4 c = child.eval(xy); xy *= 2; return c; }",
true,
true);
1475 test(
"half4 main(float2 xy) { float2 p = xy; return child.eval(p); }",
true,
true);
1477 test(
"half4 helper(float2 xy) { return child.eval(xy); }"
1478 "half4 main(float2 xy) { return helper(xy); }",
true,
true);
1481DEF_TEST(SkRuntimeShaderIsOpaque, r) {
1486 auto test = [&](
const char* body,
bool expectOpaque) {
1488 uniform shader cOnes;
1489 uniform shader cZeros;
1490 uniform float4 uOnes;
1491 uniform float4 uZeros;
1492 half4 main(float2 xy) {
1503 builder.child(
"cOnes") = std::move(cOnes);
1504 builder.child(
"cZeros") = std::move(cZeros);
1508 auto shader =
builder.makeShader();
1515 test(
"return half4(1);",
true);
1516 test(
"return half4(0, 1, 0, 1);",
true);
1517 test(
"return half4(0, 0, 0, 1);",
true);
1520 test(
"return uZeros.rgb1;",
true);
1521 test(
"return uZeros.bgra.rgb1;",
true);
1522 test(
"return half4(uZeros.rgb, 1);",
true);
1525 test(
"return cZeros.eval(xy).rgb1;",
true);
1526 test(
"return cZeros.eval(xy).bgra.rgb1;",
true);
1527 test(
"return half4(cZeros.eval(xy).rgb, 1);",
true);
1530 test(
"if (xy.x < 100) { return uZeros.rgb1; } else { return cZeros.eval(xy).rgb1; }",
true);
1533 test(
"return (cZeros.eval(xy) * uZeros).rgb1;",
true);
1534 test(
"return half4(1, 1, 1, 0.5 + 0.5);",
true);
1537 test(
"const half4 kWhite = half4(1); return kWhite;",
true);
1542 test(
"return half4(0);",
false);
1543 test(
"return half4(1, 1, 1, 0);",
false);
1546 test(
"return uZeros;",
false);
1547 test(
"return cZeros.eval(xy);",
false);
1550 test(
"if (xy.x < 100) { return uZeros; } else { return cZeros.eval(xy).rgb1; }",
false);
1551 test(
"if (xy.x < 100) { return uZeros.rgb1; } else { return cZeros.eval(xy); }",
false);
1557 test(
"return xy.x < 100 ? uZeros.rgb1 : cZeros.eval(xy).rgb1;",
false);
1562 test(
"return uOnes;",
false);
1563 test(
"return cOnes.eval(xy);",
false);
1568 std::unique_ptr<GrFragmentProcessor>
fp;
1576 "uniform half4 color;"
1577 "half4 main(float2 xy) { return color; }"
1584 result.fp->addToKey(*ctxInfo.directContext()->priv().caps()->shaderCaps(), &builder);
1589 FpAndKey uRed = make_color_fp({1, 0, 0, 1},
false),
1590 uGreen = make_color_fp({0, 1, 0, 1},
false),
1591 sRed = make_color_fp({1, 0, 0, 1},
true),
1592 sGreen = make_color_fp({0, 1, 0, 1},
true);
1609 std::unique_ptr<skgpu::ganesh::SurfaceFillContext> testCtx =
1613 static constexpr std::array<float, 4>
kRed {1.0f, 0.0f, 0.0f, 1.0f};
1614 static constexpr std::array<float, 4>
kGreen{0.0f, 1.0f, 0.0f, 1.0f};
1615 static constexpr std::array<float, 4>
kBlue {0.0f, 0.0f, 1.0f, 1.0f};
1616 static constexpr std::array<float, 4>
kGray {0.499f, 0.499f, 0.499f, 1.0f};
1621 "uniform half color[4];"
1622 "half4 main(float2 xy) { return half4(color[0], color[1], color[2], color[3]); }"
1627 "color",
SkSpan(colorArray)));
1631 if (!testCtx->readPixels(directContext, pixmap, {0, 0})) {
1635 if (actual !=
GrColorPackRGBA(255 * colorArray[0], 255 * colorArray[1],
1636 255 * colorArray[2], 255 * colorArray[3])) {
1639 "Expected: [ %g %g %g %g ]\n"
1641 colorArray[0], colorArray[1],
1642 colorArray[2], colorArray[3],
static void test_invalid(skiatest::Reporter *r, const char path[])
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static GrColor GrColorPackRGBA(unsigned r, unsigned g, unsigned b, unsigned a)
static const uint64_t kGreen
static const uint64_t kBlue
static const uint64_t kRed
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
SkColorSpace * sk_srgb_singleton()
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
constexpr SkColor SK_ColorTRANSPARENT
constexpr SkColor SK_ColorGRAY
constexpr SkColor SK_ColorBLUE
constexpr SkColor SK_ColorRED
constexpr SkColor SK_ColorBLACK
constexpr SkColor SK_ColorGREEN
constexpr SkColor SK_ColorWHITE
SkRuntimeEffect * SkMakeRuntimeEffect(SkRuntimeEffect::Result(*make)(SkString, const SkRuntimeEffect::Options &), const char *sksl, SkRuntimeEffect::Options options=SkRuntimeEffect::Options{})
static void test_RuntimeEffect_Blenders(skiatest::Reporter *r, GrRecordingContext *grContext, const GraphiteInfo *graphite)
void test_invalid_effect(skiatest::Reporter *r, const char *src, const char *expected)
static bool read_pixels(SkSurface *surface, GrColor *pixels)
static void verify_2x2_surface_results(skiatest::Reporter *r, const SkRuntimeEffect *effect, SkSurface *surface, std::array< GrColor, 4 > expected)
std::function< void(SkCanvas *, SkPaint *)> PreTestFn
static void test_RuntimeEffectObeysCapabilities(skiatest::Reporter *r, SkSurface *surface)
static sk_sp< SkShader > make_RGBW_shader()
static sk_sp< SkSurface > make_surface(GrRecordingContext *grContext, const GraphiteInfo *graphite, SkISize size)
void paint_canvas(SkCanvas *canvas, SkPaint *paint, const PreTestFn &preTestCallback)
static void verify_draw_obeys_capabilities(skiatest::Reporter *r, const SkRuntimeEffect *effect, SkSurface *surface, const SkPaint &paint)
static void test_RuntimeEffectStructNameReuse(skiatest::Reporter *r, GrRecordingContext *rContext)
static void test_RuntimeEffect_Shaders(skiatest::Reporter *r, GrRecordingContext *grContext, const GraphiteInfo *graphite)
SK_API SkString static SkString SkStringPrintf()
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
#define DEF_TEST(name, reporter)
#define REPORTER_ASSERT(r, cond,...)
#define DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(name, reporter, graphite_context, ctsEnforcement)
#define DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info, ctsEnforcement)
#define REPORT_FAILURE(reporter, cond, message)
#define DEF_GANESH_TEST_FOR_ALL_CONTEXTS(name, reporter, context_info, ctsEnforcement)
static SkScalar center(float pos0, float pos1)
GrDirectContextPriv priv()
static std::unique_ptr< GrFragmentProcessor > MakeColor(SkPMColor4f color)
std::unique_ptr< skgpu::ganesh::SurfaceFillContext > makeSFC(GrImageInfo, std::string_view label, SkBackingFit=SkBackingFit::kExact, int sampleCount=1, skgpu::Mipmapped=skgpu::Mipmapped::kNo, skgpu::Protected=skgpu::Protected::kNo, GrSurfaceOrigin=kTopLeft_GrSurfaceOrigin, skgpu::Budgeted=skgpu::Budgeted::kYes)
static GrSpecializedUniform< T > SpecializeIf(bool condition, const T &value)
static std::unique_ptr< GrSkSLFP > Make(const SkRuntimeEffect *effect, const char *name, std::unique_ptr< GrFragmentProcessor > inputFP, OptFlags optFlags, Args &&... args)
static sk_sp< SkBlender > Mode(SkBlendMode mode)
static sk_sp< SkBlender > Arithmetic(float k1, float k2, float k3, float k4, bool enforcePremul)
void drawPaint(const SkPaint &paint)
void clear(SkColor color)
void rotate(SkScalar degrees)
static sk_sp< const SkCapabilities > RasterBackend()
static sk_sp< SkColorFilter > Blend(const SkColor4f &c, sk_sp< SkColorSpace >, SkBlendMode mode)
static sk_sp< SkData > MakeEmpty()
sk_sp< SkData > detachAsData()
static sk_sp< SkShader > MakeSweep(SkScalar cx, SkScalar cy, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, SkScalar startAngle, SkScalar endAngle, uint32_t flags, const SkMatrix *localMatrix)
void setShader(sk_sp< SkShader > shader)
void setBlendMode(SkBlendMode mode)
sk_sp< SkBlender > makeBlender() const
BuilderUniform uniform(std::string_view name)
BuilderChild child(std::string_view name)
const SkRuntimeEffect * effect() const
static void AllowPrivateAccess(SkRuntimeEffect::Options *options)
static bool CanDraw(const SkCapabilities *, const SkSL::Program *)
static SkRuntimeEffect::Options ES3Options()
static Result MakeForColorFilter(SkString sksl, const Options &)
static Result MakeForBlender(SkString sksl, const Options &)
static Result MakeForShader(SkString sksl, const Options &)
static TracedShader MakeTraced(sk_sp< SkShader > shader, const SkIPoint &traceCoord)
const std::string & source() const
sk_sp< SkShader > makeShader(const SkMatrix *localMatrix=nullptr) const
constexpr size_t size() const
const char * c_str() const
T * init(Args &&... args)
void build(const char *src)
TestBlend(skiatest::Reporter *r, GrRecordingContext *grContext, const GraphiteInfo *graphite)
void test(GrColor expected, PreTestFn preTestCallback=nullptr)
SkRuntimeBlendBuilder::BuilderChild child(const char *name)
SkRuntimeBlendBuilder::BuilderUniform uniform(const char *name)
void test(std::array< GrColor, 4 > expected, PreTestFn preTestCallback=nullptr)
void test(std::array< GrColor, 4 > expected, PreTestFn preTestCallback=nullptr)
void build(const char *src)
SkRuntimeShaderBuilder::BuilderUniform uniform(const char *name)
SkRuntimeShaderBuilder::BuilderChild child(const char *name)
TestEffect(skiatest::Reporter *r, GrRecordingContext *grContext, const GraphiteInfo *graphite, SkISize size={2, 2})
void test(GrColor expected, PreTestFn preTestCallback=nullptr)
std::string trace(const SkIPoint &traceCoord)
FlutterSemanticsFlag flags
const uint8_t uint32_t uint32_t GError ** error
constexpr SkColor4f kWhite
constexpr SkColor4f kTransparent
constexpr SkColor4f kGray
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
constexpr bool starts_with(std::string_view str, std::string_view prefix)
constexpr bool ends_with(std::string_view str, std::string_view suffix)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
sk_sp< SkRuntimeEffect > effect