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 "src/base/SkArenaAlloc.h"
11 #include "src/core/SkRasterPipeline.h"
12 #include "src/sksl/SkSLCompiler.h"
13 #include "src/sksl/SkSLProgramKind.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/SkSLDebugTracePriv.h"
21 #include "tests/Test.h"
22
23 #include <memory>
24 #include <optional>
25 #include <sstream>
26 #include <string>
27
28 //#define DUMP_PROGRAMS 1
29 #if defined(DUMP_PROGRAMS)
30 #include "src/core/SkStreamPriv.h"
31 #endif
32
test(skiatest::Reporter * r,const char * src,SkSpan<const float> uniforms,SkColor4f startingColor,std::optional<SkColor4f> expectedResult)33 static void test(skiatest::Reporter* r,
34 const char* src,
35 SkSpan<const float> uniforms,
36 SkColor4f startingColor,
37 std::optional<SkColor4f> expectedResult) {
38 SkSL::Compiler compiler;
39 SkSL::ProgramSettings settings;
40 settings.fMaxVersionAllowed = SkSL::Version::k300;
41 std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
42 SkSL::ProgramKind::kRuntimeColorFilter, std::string(src), settings);
43 if (!program) {
44 ERRORF(r, "Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
45 return;
46 }
47 const SkSL::FunctionDeclaration* main = program->getFunction("main");
48 if (!main) {
49 ERRORF(r, "Program must have a 'main' function");
50 return;
51 }
52 SkArenaAlloc alloc(/*firstHeapAllocation=*/1000);
53 SkRasterPipeline pipeline(&alloc);
54 pipeline.appendConstantColor(&alloc, startingColor);
55 SkSL::DebugTracePriv debugTrace;
56 std::unique_ptr<SkSL::RP::Program> rasterProg =
57 SkSL::MakeRasterPipelineProgram(*program, *main->definition(), &debugTrace);
58 if (!rasterProg && !expectedResult.has_value()) {
59 // We didn't get a program, as expected. Test passes.
60 return;
61 }
62 if (!rasterProg && expectedResult.has_value()) {
63 ERRORF(r, "MakeRasterPipelineProgram failed");
64 return;
65 }
66 if (rasterProg && !expectedResult.has_value()) {
67 ERRORF(r, "MakeRasterPipelineProgram should have failed, but didn't");
68 return;
69 }
70
71 #if defined(DUMP_PROGRAMS)
72 // Dump the program instructions via SkDebugf.
73 SkDebugf("-----\n\n");
74 SkDebugfStream stream;
75 rasterProg->dump(&stream);
76 SkDebugf("\n-----\n\n");
77 #endif
78
79 // Append the SkSL program to the raster pipeline.
80 rasterProg->appendStages(&pipeline, &alloc, /*callbacks=*/nullptr, uniforms);
81
82 // Move the float values from RGBA into an 8888 memory buffer.
83 uint32_t out[SkRasterPipeline_kMaxStride_highp] = {};
84 SkRasterPipeline_MemoryCtx outCtx{/*pixels=*/out, /*stride=*/SkRasterPipeline_kMaxStride_highp};
85 pipeline.append(SkRasterPipelineOp::store_8888, &outCtx);
86 pipeline.run(0, 0, 1, 1);
87
88 // Make sure the first pixel (exclusively) of `out` matches RGBA.
89 uint32_t expected = expectedResult->toBytes_RGBA();
90 REPORTER_ASSERT(r, out[0] == expected,
91 "Got:%02X%02X%02X%02X Expected:%02X%02X%02X%02X",
92 (out[0] >> 24) & 0xFF,
93 (out[0] >> 16) & 0xFF,
94 (out[0] >> 8) & 0xFF,
95 out[0] & 0xFF,
96 (expected >> 24) & 0xFF,
97 (expected >> 16) & 0xFF,
98 (expected >> 8) & 0xFF,
99 expected & 0xFF);
100
101 // Make sure the rest of the pixels are untouched.
102 for (size_t i = 1; i < std::size(out); ++i) {
103 REPORTER_ASSERT(r, out[i] == 0);
104 }
105 }
106
DEF_TEST(SkSLRasterPipelineCodeGeneratorNestedTernaryTest,r)107 DEF_TEST(SkSLRasterPipelineCodeGeneratorNestedTernaryTest, r) {
108 // Add in your SkSL here.
109 test(r,
110 R"__SkSL__(
111 half4 main(half4) {
112 half three = 3, one = 1, two = 2;
113 half result = (three > (one > two ? 2.0 : 5.0)) ? 1.0 : 0.499;
114 return half4(result);
115 }
116 )__SkSL__",
117 /*uniforms=*/{},
118 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
119 /*expectedResult=*/SkColor4f{0.499f, 0.499f, 0.499f, 0.499f});
120 }
121
DEF_TEST(SkSLRasterPipelineCodeGeneratorArithmeticTest,r)122 DEF_TEST(SkSLRasterPipelineCodeGeneratorArithmeticTest, r) {
123 test(r,
124 R"__SkSL__(
125 half4 main(half4) {
126 const half4 colorGreen = half4(0,1,0,1), colorRed = half4(1,0,0,1);
127
128 half a = 3.0, b = 4.0, c = a + b - 2.0;
129 if (a*a + b*b == c*c*c/5.0) {
130 int A = 3, B = 4, C = A + B - 2;
131 if (A*A + B*B == C*C*C/5) {
132 return colorGreen;
133 }
134 }
135
136 return colorRed;
137 }
138 )__SkSL__",
139 /*uniforms=*/{},
140 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
141 /*expectedResult=*/SkColor4f{0.0f, 1.0f, 0.0f, 1.0f});
142 }
143
DEF_TEST(SkSLRasterPipelineCodeGeneratorCoercedTypeTest,r)144 DEF_TEST(SkSLRasterPipelineCodeGeneratorCoercedTypeTest, r) {
145 static constexpr float kUniforms[] = {0.0, 1.0, 0.0, 1.0,
146 1.0, 0.0, 0.0, 1.0};
147 test(r,
148 R"__SkSL__(
149 uniform half4 colorGreen;
150 uniform float4 colorRed;
151 half4 main(half4 color) {
152 return ((colorGreen + colorRed) == float4(1.0, 1.0, 0.0, 2.0)) ? colorGreen
153 : colorGreen.gr01;
154 }
155 )__SkSL__",
156 kUniforms,
157 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
158 /*expectedResult=*/SkColor4f{0.0, 1.0, 0.0, 1.0});
159 }
160
DEF_TEST(SkSLRasterPipelineCodeGeneratorIdentitySwizzle,r)161 DEF_TEST(SkSLRasterPipelineCodeGeneratorIdentitySwizzle, r) {
162 static constexpr float kUniforms[] = {0.0, 1.0, 0.0, 1.0,
163 1.0, 0.0, 0.0, 1.0};
164 test(r,
165 R"__SkSL__(
166
167 uniform half4 colorGreen, colorRed;
168
169 const int SEVEN = 7, TEN = 10;
170 const half4x4 MATRIXFIVE = half4x4(5);
171
172 noinline bool verify_const_globals(int seven, int ten, half4x4 matrixFive) {
173 return seven == 7 && ten == 10 && matrixFive == half4x4(5);
174 }
175
176 half4 main(float4) {
177 return verify_const_globals(SEVEN, TEN, MATRIXFIVE) ? colorGreen : colorRed;
178 }
179
180 )__SkSL__",
181 kUniforms,
182 /*startingColor=*/SkColor4f{0.5, 1.0, 0.0, 0.25},
183 /*expectedResult=*/SkColor4f{0.0, 1.0, 0.0, 1.0});
184
185 }
186
DEF_TEST(SkSLRasterPipelineCodeGeneratorBitwiseNotTest,r)187 DEF_TEST(SkSLRasterPipelineCodeGeneratorBitwiseNotTest, r) {
188 static constexpr int32_t kUniforms[] = { 0, 12, 3456, 4567890,
189 ~0, ~12, ~3456, ~4567890};
190 test(r,
191 R"__SkSL__(
192 uniform int4 value, expected;
193 const half4 colorGreen = half4(0,1,0,1), colorRed = half4(1,0,0,1);
194
195 half4 main(vec4) {
196 return (~value.x == expected.x &&
197 ~value.xy == expected.xy &&
198 ~value.xyz == expected.xyz &&
199 ~value.xyzw == expected.xyzw) ? colorGreen : colorRed;
200 }
201 )__SkSL__",
202 SkSpan((const float*)kUniforms, std::size(kUniforms)),
203 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
204 /*expectedResult=*/SkColor4f{0.0, 1.0, 0.0, 1.0});
205 }
206
DEF_TEST(SkSLRasterPipelineCodeGeneratorComparisonIntrinsicTest,r)207 DEF_TEST(SkSLRasterPipelineCodeGeneratorComparisonIntrinsicTest, r) {
208 test(r,
209 R"__SkSL__(
210 half4 main(vec4) {
211 const half4 colorGreen = half4(0,1,0,1), colorRed = half4(1,0,0,1);
212 half4 a = half4(1, 2, 0, 1),
213 b = half4(2, 2, 1, 0);
214 int3 c = int3(1111, 3333, 5555),
215 d = int3(1111, 5555, 3333);
216 uint2 e = uint2(1111111111u, 222),
217 f = uint2(3333333333u, 222);
218 return (lessThan(a, b) == bool4(true, false, true, false) &&
219 lessThan(c, d) == bool3(false, true, false) &&
220 lessThan(e, f) == bool2(true, false) &&
221 greaterThan(a, b) == bool4(false, false, false, true) &&
222 greaterThan(c, d) == bool3(false, false, true) &&
223 greaterThan(e, f) == bool2(false, false) &&
224 lessThanEqual(a, b) == bool4(true, true, true, false) &&
225 lessThanEqual(c, d) == bool3(true, true, false) &&
226 lessThanEqual(e, f) == bool2(true, true) &&
227 greaterThanEqual(a, b) == bool4(false, true, false, true) &&
228 greaterThanEqual(c, d) == bool3(true, false, true) &&
229 greaterThanEqual(e, f) == bool2(false, true) &&
230 equal(a, b) == bool4(false, true, false, false) &&
231 equal(c, d) == bool3(true, false, false) &&
232 equal(e, f) == bool2(false, true) &&
233 notEqual(a, b) == bool4(true, false, true, true) &&
234 notEqual(c, d) == bool3(false, true, true) &&
235 notEqual(e, f) == bool2(true, false) &&
236 max(a, b) == half4(2, 2, 1, 1) &&
237 max(c, d) == int3(1111, 5555, 5555) &&
238 max(e, f) == uint2(3333333333u, 222) &&
239 max(a, 1) == half4(1, 2, 1, 1) &&
240 max(c, 3333) == int3(3333, 3333, 5555) &&
241 max(e, 7777) == uint2(1111111111u, 7777) &&
242 min(a, b) == half4(1, 2, 0, 0) &&
243 min(c, d) == int3(1111, 3333, 3333) &&
244 min(e, f) == uint2(1111111111u, 222) &&
245 min(a, 1) == half4(1, 1, 0, 1) &&
246 min(c, 3333) == int3(1111, 3333, 3333) &&
247 min(e, 7777) == uint2(7777, 222)) ? colorGreen : colorRed;
248 }
249 )__SkSL__",
250 /*uniforms=*/{},
251 /*startingColor=*/SkColor4f{0.0, 0.0, 0.0, 0.0},
252 /*expectedResult=*/SkColor4f{0.0, 1.0, 0.0, 1.0});
253 }
254
DEF_TEST(SkSLRasterPipelineSlotOverflow_355465305,r)255 DEF_TEST(SkSLRasterPipelineSlotOverflow_355465305, r) {
256 constexpr int kStructMembers1 = 6200;
257 constexpr int kStructMembers2 = 433;
258 std::stringstream str;
259 str << "struct M { float4x4 m";
260 for (int i = 1; i < kStructMembers1; ++i) {
261 str << ",m" << i;
262 }
263 str << ";};";
264 str << "struct M2 { float4x4 m";
265 for (int i = 1; i < kStructMembers2; ++i) {
266 str << ",m" << i;
267 }
268 str << ";};";
269 str << "M f() { M m; return m; }";
270 constexpr int kConstMembers = 40;
271 str << "struct T { float4x4 m0";
272 for (int i = 1; i < kConstMembers; ++i) {
273 str << ",m" << i;
274 }
275 str << ";};";
276 str << "const T K = T(";
277 for (int i = 0; i < kConstMembers; ++i) {
278 if (i > 0) {
279 str << ",";
280 }
281 str << "mat4x4(1337)";
282 }
283 str << ");";
284 str << "half4 main(half4 color) {";
285 str << "float4x4 a = M2(";
286 for (int j = 0; j < kStructMembers2; ++j) {
287 if (j > 0) {
288 str << ",";
289 }
290 const int numAddOps = (j == kStructMembers1 - 1) ? 23 : 25;
291 for (int i = 0; i < numAddOps; ++i) {
292 if (i > 0) {
293 str << "+";
294 }
295 str << "f().m";
296 }
297 }
298 str << ").m;";
299 str << "return half4(a[0]+(K.m0+K.m1+K.m2+K.m3)[0]);";
300 str << "}";
301 std::string src = str.str();
302
303 SkSL::Compiler compiler;
304 std::unique_ptr<SkSL::Program> program =
305 compiler.convertProgram(SkSL::ProgramKind::kRuntimeColorFilter, src, {});
306 if (!program) {
307 ERRORF(r, "Unexpected error compiling %s\n%s", src.c_str(), compiler.errorText().c_str());
308 return;
309 }
310 const SkSL::FunctionDeclaration* main = program->getFunction("main");
311 if (!main) {
312 ERRORF(r, "Program must have a 'main' function");
313 return;
314 }
315 SkArenaAlloc alloc(1000);
316 SkRasterPipeline pipeline(&alloc);
317 pipeline.appendConstantColor(&alloc, SkColors::kWhite);
318 std::unique_ptr<SkSL::RP::Program> rasterProg =
319 SkSL::MakeRasterPipelineProgram(*program, *main->definition());
320 // Ideally, this program would fail in the front-end, because of the number of slots needed
321 // for expression evaluation. For now, it succeeds (but then fails in appendStages).
322 if (!rasterProg) {
323 ERRORF(r, "MakeRasterPipelineProgram failed");
324 return;
325 }
326
327 // Append the SkSL program to the raster pipeline.
328 bool success = rasterProg->appendStages(&pipeline, &alloc, /*callbacks=*/nullptr, {});
329 REPORTER_ASSERT(r, !success, "appendStages should fail for very large program");
330 }
331