1 /*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkColor.h"
9 #include "include/core/SkTypes.h"
10 #include "include/private/SkSLProgramKind.h"
11 #include "src/base/SkArenaAlloc.h"
12 #include "src/core/SkRasterPipeline.h"
13 #include "src/sksl/SkSLCompiler.h"
14 #include "src/sksl/SkSLProgramSettings.h"
15 #include "src/sksl/SkSLUtil.h"
16 #include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
17 #include "src/sksl/codegen/SkSLRasterPipelineCodeGenerator.h"
18 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
19 #include "src/sksl/ir/SkSLProgram.h"
20 #include "src/sksl/tracing/SkRPDebugTrace.h"
21 #include "tests/Test.h"
22
23 #include <memory>
24 #include <optional>
25 #include <string>
26
27 //#define DUMP_PROGRAMS 1
28 #if defined(DUMP_PROGRAMS)
29 #include "src/core/SkStreamPriv.h"
30 #endif
31
test(skiatest::Reporter * r,const char * src,SkSpan<const float> uniforms,SkColor4f startingColor,std::optional<SkColor4f> expectedResult)32 static void test(skiatest::Reporter* r,
33 const char* src,
34 SkSpan<const float> uniforms,
35 SkColor4f startingColor,
36 std::optional<SkColor4f> expectedResult) {
37 SkSL::Compiler compiler(SkSL::ShaderCapsFactory::Default());
38 SkSL::ProgramSettings settings;
39 settings.fMaxVersionAllowed = SkSL::Version::k300;
40 std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
41 SkSL::ProgramKind::kRuntimeColorFilter, std::string(src), settings);
42 if (!program) {
43 ERRORF(r, "Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
44 return;
45 }
46 const SkSL::FunctionDeclaration* main = program->getFunction("main");
47 if (!main) {
48 ERRORF(r, "Program must have a 'main' function");
49 return;
50 }
51 SkArenaAlloc alloc(/*firstHeapAllocation=*/1000);
52 SkRasterPipeline pipeline(&alloc);
53 pipeline.append_constant_color(&alloc, startingColor);
54 SkSL::SkRPDebugTrace debugTrace;
55 std::unique_ptr<SkSL::RP::Program> rasterProg =
56 SkSL::MakeRasterPipelineProgram(*program, *main->definition(), &debugTrace);
57 if (!rasterProg && !expectedResult.has_value()) {
58 // We didn't get a program, as expected. Test passes.
59 return;
60 }
61 if (!rasterProg && expectedResult.has_value()) {
62 ERRORF(r, "MakeRasterPipelineProgram failed");
63 return;
64 }
65 if (rasterProg && !expectedResult.has_value()) {
66 ERRORF(r, "MakeRasterPipelineProgram should have failed, but didn't");
67 return;
68 }
69
70 #if defined(DUMP_PROGRAMS)
71 // Dump the program instructions via SkDebugf.
72 SkDebugf("-----\n\n");
73 SkDebugfStream stream;
74 rasterProg->dump(&stream);
75 SkDebugf("\n-----\n\n");
76 #endif
77
78 // Append the SkSL program to the raster pipeline.
79 rasterProg->appendStages(&pipeline, &alloc, /*callbacks=*/nullptr, uniforms);
80
81 // Move the float values from RGBA into an 8888 memory buffer.
82 uint32_t out[SkRasterPipeline_kMaxStride_highp] = {};
83 SkRasterPipeline_MemoryCtx outCtx{/*pixels=*/out, /*stride=*/SkRasterPipeline_kMaxStride_highp};
84 pipeline.append(SkRasterPipelineOp::store_8888, &outCtx);
85 pipeline.run(0, 0, 1, 1);
86
87 // Make sure the first pixel (exclusively) of `out` matches RGBA.
88 uint32_t expected = expectedResult->toBytes_RGBA();
89 REPORTER_ASSERT(r, out[0] == expected,
90 "Got:%02X%02X%02X%02X Expected:%02X%02X%02X%02X",
91 (out[0] >> 24) & 0xFF,
92 (out[0] >> 16) & 0xFF,
93 (out[0] >> 8) & 0xFF,
94 out[0] & 0xFF,
95 (expected >> 24) & 0xFF,
96 (expected >> 16) & 0xFF,
97 (expected >> 8) & 0xFF,
98 expected & 0xFF);
99
100 // Make sure the rest of the pixels are untouched.
101 for (size_t i = 1; i < std::size(out); ++i) {
102 REPORTER_ASSERT(r, out[i] == 0);
103 }
104 }
105
DEF_TEST(SkSLRasterPipelineCodeGeneratorIfElseTest,r)106 DEF_TEST(SkSLRasterPipelineCodeGeneratorIfElseTest, r) {
107 // Add in your SkSL here.
108 test(r,
109 R"__SkSL__(
110 const half4 colorWhite = half4(1);
111
112 half4 ifElseTest(half4 colorBlue, half4 colorGreen, half4 colorRed) {
113 half4 result = half4(0);
114 if (colorWhite != colorBlue) { // TRUE
115 if (colorGreen == colorRed) { // FALSE
116 result = colorRed;
117 } else {
118 result = colorGreen;
119 }
120 } else {
121 if (colorRed != colorGreen) { // TRUE, but in a false branch
122 result = colorBlue;
123 } else { // FALSE, and in a false branch
124 result = colorWhite;
125 }
126 }
127 if (colorRed == colorBlue) { // FALSE
128 return colorWhite;
129 }
130 if (colorRed != colorGreen) { // TRUE
131 return result;
132 }
133 if (colorRed == colorWhite) { // FALSE
134 return colorBlue;
135 }
136 return colorRed;
137 }
138
139 half4 main(half4) {
140 return ifElseTest(colorWhite.00b1, colorWhite.0g01, colorWhite.r001);
141 }
142 )__SkSL__",
143 /*uniforms=*/{},
144 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
145 /*expectedResult=*/SkColor4f{0.0f, 1.0f, 0.0f, 1.0f});
146 }
147
DEF_TEST(SkSLRasterPipelineCodeGeneratorTernaryTest,r)148 DEF_TEST(SkSLRasterPipelineCodeGeneratorTernaryTest, r) {
149 // Add in your SkSL here.
150 test(r,
151 R"__SkSL__(
152 half4 main(half4 colorWhite) {
153 half4 colorBlue = colorWhite.00ba,
154 colorGreen = colorWhite.0g0a,
155 colorRed = colorWhite.r00a;
156 // This ternary matches the initial if-else block inside IfElseTest.
157 half4 result;
158 result = (colorWhite != colorBlue) // TRUE
159 ? (colorGreen == colorRed ? colorRed : colorGreen) // FALSE
160 : (colorRed != colorGreen ? colorBlue : colorWhite); // in false branch
161
162 // This ternary matches the second portion of IfElseTest.
163 return colorRed == colorBlue ? colorWhite :
164 colorRed != colorGreen ? result : // TRUE
165 colorRed == colorWhite ? colorBlue :
166 colorRed;
167 }
168 )__SkSL__",
169 /*uniforms=*/{},
170 /*startingColor=*/SkColor4f{1.0, 1.0, 1.0, 1.0},
171 /*expectedResult=*/SkColor4f{0.0f, 1.0f, 0.0f, 1.0f});
172 }
173
DEF_TEST(SkSLRasterPipelineCodeGeneratorNestedTernaryTest,r)174 DEF_TEST(SkSLRasterPipelineCodeGeneratorNestedTernaryTest, r) {
175 // Add in your SkSL here.
176 test(r,
177 R"__SkSL__(
178 half4 main(half4) {
179 half three = 3, one = 1, two = 2;
180 half result = (three > (one > two ? 2.0 : 5.0)) ? 1.0 : 0.499;
181 return half4(result);
182 }
183 )__SkSL__",
184 /*uniforms=*/{},
185 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
186 /*expectedResult=*/SkColor4f{0.499f, 0.499f, 0.499f, 0.499f});
187 }
188
DEF_TEST(SkSLRasterPipelineCodeGeneratorArithmeticTest,r)189 DEF_TEST(SkSLRasterPipelineCodeGeneratorArithmeticTest, r) {
190 test(r,
191 R"__SkSL__(
192 half4 main(half4) {
193 const half4 colorGreen = half4(0,1,0,1), colorRed = half4(1,0,0,1);
194
195 half a = 3.0, b = 4.0, c = a + b - 2.0;
196 if (a*a + b*b == c*c*c/5.0) {
197 int A = 3, B = 4, C = A + B - 2;
198 if (A*A + B*B == C*C*C/5) {
199 return colorGreen;
200 }
201 }
202
203 return colorRed;
204 }
205 )__SkSL__",
206 /*uniforms=*/{},
207 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
208 /*expectedResult=*/SkColor4f{0.0f, 1.0f, 0.0f, 1.0f});
209 }
210
DEF_TEST(SkSLRasterPipelineCodeGeneratorCoercedTypeTest,r)211 DEF_TEST(SkSLRasterPipelineCodeGeneratorCoercedTypeTest, r) {
212 static constexpr float kUniforms[] = {0.0, 1.0, 0.0, 1.0,
213 1.0, 0.0, 0.0, 1.0};
214 test(r,
215 R"__SkSL__(
216 uniform half4 colorGreen;
217 uniform float4 colorRed;
218 half4 main(half4 color) {
219 return ((colorGreen + colorRed) == float4(1.0, 1.0, 0.0, 2.0)) ? colorGreen
220 : colorGreen.gr01;
221 }
222 )__SkSL__",
223 kUniforms,
224 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
225 /*expectedResult=*/SkColor4f{0.0, 1.0, 0.0, 1.0});
226 }
227
DEF_TEST(SkSLRasterPipelineCodeGeneratorIdentitySwizzle,r)228 DEF_TEST(SkSLRasterPipelineCodeGeneratorIdentitySwizzle, r) {
229 static constexpr float kUniforms[] = {0.0, 1.0, 0.0, 1.0,
230 1.0, 0.0, 0.0, 1.0};
231 test(r,
232 R"__SkSL__(
233 uniform half4 colorGreen, colorRed;
234 half4 main(vec4 color) {
235 return (color.r == 0.5 &&
236 color.rg == half2(0.5, 1.0) &&
237 color.rgb == half3(0.5, 1.0, 0.0)) ? colorGreen : colorRed;
238 }
239 )__SkSL__",
240 kUniforms,
241 /*startingColor=*/SkColor4f{0.5, 1.0, 0.0, 0.25},
242 /*expectedResult=*/SkColor4f{0.0, 1.0, 0.0, 1.0});
243
244 }
245
DEF_TEST(SkSLRasterPipelineCodeGeneratorBitwiseNotTest,r)246 DEF_TEST(SkSLRasterPipelineCodeGeneratorBitwiseNotTest, r) {
247 static constexpr int32_t kUniforms[] = { 0, 12, 3456, 4567890,
248 ~0, ~12, ~3456, ~4567890};
249 test(r,
250 R"__SkSL__(
251 uniform int4 value, expected;
252 const half4 colorGreen = half4(0,1,0,1), colorRed = half4(1,0,0,1);
253
254 half4 main(vec4) {
255 return (~value.x == expected.x &&
256 ~value.xy == expected.xy &&
257 ~value.xyz == expected.xyz &&
258 ~value.xyzw == expected.xyzw) ? colorGreen : colorRed;
259 }
260 )__SkSL__",
261 SkSpan((const float*)kUniforms, std::size(kUniforms)),
262 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
263 /*expectedResult=*/SkColor4f{0.0, 1.0, 0.0, 1.0});
264 }
265
DEF_TEST(SkSLRasterPipelineCodeGeneratorComparisonIntrinsicTest,r)266 DEF_TEST(SkSLRasterPipelineCodeGeneratorComparisonIntrinsicTest, r) {
267 test(r,
268 R"__SkSL__(
269 half4 main(vec4) {
270 const half4 colorGreen = half4(0,1,0,1), colorRed = half4(1,0,0,1);
271 half4 a = half4(1, 2, 0, 1),
272 b = half4(2, 2, 1, 0);
273 int3 c = int3(1111, 3333, 5555),
274 d = int3(1111, 5555, 3333);
275 uint2 e = uint2(1111111111u, 222),
276 f = uint2(3333333333u, 222);
277 return (lessThan(a, b) == bool4(true, false, true, false) &&
278 lessThan(c, d) == bool3(false, true, false) &&
279 lessThan(e, f) == bool2(true, false) &&
280 greaterThan(a, b) == bool4(false, false, false, true) &&
281 greaterThan(c, d) == bool3(false, false, true) &&
282 greaterThan(e, f) == bool2(false, false) &&
283 lessThanEqual(a, b) == bool4(true, true, true, false) &&
284 lessThanEqual(c, d) == bool3(true, true, false) &&
285 lessThanEqual(e, f) == bool2(true, true) &&
286 greaterThanEqual(a, b) == bool4(false, true, false, true) &&
287 greaterThanEqual(c, d) == bool3(true, false, true) &&
288 greaterThanEqual(e, f) == bool2(false, true) &&
289 equal(a, b) == bool4(false, true, false, false) &&
290 equal(c, d) == bool3(true, false, false) &&
291 equal(e, f) == bool2(false, true) &&
292 notEqual(a, b) == bool4(true, false, true, true) &&
293 notEqual(c, d) == bool3(false, true, true) &&
294 notEqual(e, f) == bool2(true, false) &&
295 max(a, b) == half4(2, 2, 1, 1) &&
296 max(c, d) == int3(1111, 5555, 5555) &&
297 max(e, f) == uint2(3333333333u, 222) &&
298 max(a, 1) == half4(1, 2, 1, 1) &&
299 max(c, 3333) == int3(3333, 3333, 5555) &&
300 max(e, 7777) == uint2(1111111111u, 7777) &&
301 min(a, b) == half4(1, 2, 0, 0) &&
302 min(c, d) == int3(1111, 3333, 3333) &&
303 min(e, f) == uint2(1111111111u, 222) &&
304 min(a, 1) == half4(1, 1, 0, 1) &&
305 min(c, 3333) == int3(1111, 3333, 3333) &&
306 min(e, 7777) == uint2(7777, 222)) ? colorGreen : colorRed;
307 }
308 )__SkSL__",
309 /*uniforms=*/{},
310 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
311 /*expectedResult=*/SkColor4f{0.0, 1.0, 0.0, 1.0});
312 }
313