xref: /aosp_15_r20/external/skia/tests/RasterPipelineCodeGeneratorTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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