1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2019 Google LLC
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkM44.h"
9cb93a386Sopenharmony_ci#include "src/sksl/SkSLCompiler.h"
10cb93a386Sopenharmony_ci#include "src/sksl/codegen/SkSLVMCodeGenerator.h"
11cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLExternalFunction.h"
12cb93a386Sopenharmony_ci#include "src/utils/SkJSON.h"
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_ci#include "tests/Test.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_cistruct ProgramBuilder {
17cb93a386Sopenharmony_ci    ProgramBuilder(skiatest::Reporter* r, const char* src)
18cb93a386Sopenharmony_ci            : fCompiler(&fCaps) {
19cb93a386Sopenharmony_ci        SkSL::Program::Settings settings;
20cb93a386Sopenharmony_ci        // The SkSL inliner is well tested in other contexts. Here, we disable inlining entirely,
21cb93a386Sopenharmony_ci        // to stress-test the VM generator's handling of function calls with varying signatures.
22cb93a386Sopenharmony_ci        settings.fInlineThreshold = 0;
23cb93a386Sopenharmony_ci        // For convenience, so we can test functions other than (and not called by) main.
24cb93a386Sopenharmony_ci        settings.fRemoveDeadFunctions = false;
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci        fProgram = fCompiler.convertProgram(SkSL::ProgramKind::kGeneric, SkSL::String(src),
27cb93a386Sopenharmony_ci                                            settings);
28cb93a386Sopenharmony_ci        if (!fProgram) {
29cb93a386Sopenharmony_ci            ERRORF(r, "Program failed to compile:\n%s\n%s\n", src, fCompiler.errorText().c_str());
30cb93a386Sopenharmony_ci        }
31cb93a386Sopenharmony_ci    }
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_ci    operator bool() const { return fProgram != nullptr; }
34cb93a386Sopenharmony_ci    SkSL::Program& operator*() { return *fProgram; }
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci    GrShaderCaps fCaps;
37cb93a386Sopenharmony_ci    SkSL::Compiler fCompiler;
38cb93a386Sopenharmony_ci    std::unique_ptr<SkSL::Program> fProgram;
39cb93a386Sopenharmony_ci};
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_cistatic void verify_values(skiatest::Reporter* r,
42cb93a386Sopenharmony_ci                          const char* src,
43cb93a386Sopenharmony_ci                          const float* actual,
44cb93a386Sopenharmony_ci                          const float* expected,
45cb93a386Sopenharmony_ci                          int N,
46cb93a386Sopenharmony_ci                          bool exactCompare) {
47cb93a386Sopenharmony_ci    auto exact_equiv = [](float x, float y) {
48cb93a386Sopenharmony_ci        return x == y
49cb93a386Sopenharmony_ci            || (isnan(x) && isnan(y));
50cb93a386Sopenharmony_ci    };
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci    bool valid = true;
53cb93a386Sopenharmony_ci    for (int i = 0; i < N; ++i) {
54cb93a386Sopenharmony_ci        if (exactCompare && !exact_equiv(actual[i], expected[i])) {
55cb93a386Sopenharmony_ci            valid = false;
56cb93a386Sopenharmony_ci        }
57cb93a386Sopenharmony_ci        if (!exactCompare && !SkScalarNearlyEqual(actual[i], expected[i])) {
58cb93a386Sopenharmony_ci            valid = false;
59cb93a386Sopenharmony_ci        }
60cb93a386Sopenharmony_ci    }
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci    if (!valid) {
63cb93a386Sopenharmony_ci        printf("for program: %s\n", src);
64cb93a386Sopenharmony_ci        printf("    expected (");
65cb93a386Sopenharmony_ci        const char* separator = "";
66cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
67cb93a386Sopenharmony_ci            printf("%s%f", separator, expected[i]);
68cb93a386Sopenharmony_ci            separator = ", ";
69cb93a386Sopenharmony_ci        }
70cb93a386Sopenharmony_ci        printf("), but received (");
71cb93a386Sopenharmony_ci        separator = "";
72cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
73cb93a386Sopenharmony_ci            printf("%s%f", separator, actual[i]);
74cb93a386Sopenharmony_ci            separator = ", ";
75cb93a386Sopenharmony_ci        }
76cb93a386Sopenharmony_ci        printf(")\n");
77cb93a386Sopenharmony_ci    }
78cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, valid);
79cb93a386Sopenharmony_ci}
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_civoid test(skiatest::Reporter* r, const char* src, float* in, const float* expected,
82cb93a386Sopenharmony_ci          bool exactCompare = true) {
83cb93a386Sopenharmony_ci    ProgramBuilder program(r, src);
84cb93a386Sopenharmony_ci    if (!program) { return; }
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci    const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
87cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, main);
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci    skvm::Builder b;
90cb93a386Sopenharmony_ci    SkSL::SkVMSignature sig;
91cb93a386Sopenharmony_ci    SkSL::ProgramToSkVM(*program, *main, &b, /*debugInfo=*/nullptr, /*uniforms=*/{}, &sig);
92cb93a386Sopenharmony_ci    skvm::Program p = b.done();
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, p.nargs() == (int)(sig.fParameterSlots + sig.fReturnSlots));
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci    auto out = std::make_unique<float[]>(sig.fReturnSlots);
97cb93a386Sopenharmony_ci    auto args = std::make_unique<void*[]>(sig.fParameterSlots + sig.fReturnSlots);
98cb93a386Sopenharmony_ci    for (size_t i = 0; i < sig.fParameterSlots; ++i) {
99cb93a386Sopenharmony_ci        args[i] = in + i;
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci    for (size_t i = 0; i < sig.fReturnSlots; ++i) {
102cb93a386Sopenharmony_ci        args[sig.fParameterSlots + i] = out.get() + i;
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci    // TODO: Test with and without JIT?
106cb93a386Sopenharmony_ci    p.eval(1, args.get());
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ci    verify_values(r, src, out.get(), expected, sig.fReturnSlots, exactCompare);
109cb93a386Sopenharmony_ci}
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_civoid test(skiatest::Reporter* r, const char* src,
112cb93a386Sopenharmony_ci          float inR, float inG, float inB, float inA,
113cb93a386Sopenharmony_ci          float exR, float exG, float exB, float exA) {
114cb93a386Sopenharmony_ci    ProgramBuilder program(r, src);
115cb93a386Sopenharmony_ci    if (!program) { return; }
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci    const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
118cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, main);
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ci    skvm::Builder b;
121cb93a386Sopenharmony_ci    SkSL::ProgramToSkVM(*program, *main, &b, /*debugInfo=*/nullptr, /*uniforms=*/{});
122cb93a386Sopenharmony_ci    skvm::Program p = b.done();
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ci    // TODO: Test with and without JIT?
125cb93a386Sopenharmony_ci    p.eval(1, &inR, &inG, &inB, &inA);
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci    float actual[4]   = { inR, inG, inB, inA };
128cb93a386Sopenharmony_ci    float expected[4] = { exR, exG, exB, exA };
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci    verify_values(r, src, actual, expected, 4, /*exactCompare=*/true);
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci    // TODO: vec_test with skvm
133cb93a386Sopenharmony_ci}
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterAdd, r) {
136cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = color.r + color.g; }", 0.25, 0.75, 0, 0, 1,
137cb93a386Sopenharmony_ci         0.75, 0, 0);
138cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color += half4(1, 2, 3, 4); }", 4, 3, 2, 1, 5, 5, 5, 5);
139cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { half4 c = color; color += c; }", 0.25, 0.5, 0.75, 1,
140cb93a386Sopenharmony_ci         0.5, 1, 1.5, 2);
141cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = half(int(color.r) + int(color.g)); }", 1, 3, 0, 0,
142cb93a386Sopenharmony_ci         4, 3, 0, 0);
143cb93a386Sopenharmony_ci}
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterSubtract, r) {
146cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = color.r - color.g; }", 1, 0.75, 0, 0, 0.25,
147cb93a386Sopenharmony_ci         0.75, 0, 0);
148cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color -= half4(1, 2, 3, 4); }", 5, 5, 5, 5, 4, 3, 2, 1);
149cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { half4 c = color; color -= c; }", 4, 3, 2, 1,
150cb93a386Sopenharmony_ci         0, 0, 0, 0);
151cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.x = -color.x; }", 4, 3, 2, 1, -4, 3, 2, 1);
152cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color = -color; }", 4, 3, 2, 1, -4, -3, -2, -1);
153cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = half(int(color.r) - int(color.g)); }", 3, 1, 0, 0,
154cb93a386Sopenharmony_ci         2, 1, 0, 0);
155cb93a386Sopenharmony_ci}
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterMultiply, r) {
158cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = color.r * color.g; }", 2, 3, 0, 0, 6, 3, 0,
159cb93a386Sopenharmony_ci         0);
160cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color *= half4(1, 2, 3, 4); }", 2, 3, 4, 5, 2, 6, 12,
161cb93a386Sopenharmony_ci         20);
162cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { half4 c = color; color *= c; }", 4, 3, 2, 1,
163cb93a386Sopenharmony_ci         16, 9, 4, 1);
164cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = half(int(color.r) * int(color.g)); }", 3, -2, 0, 0,
165cb93a386Sopenharmony_ci         -6, -2, 0, 0);
166cb93a386Sopenharmony_ci}
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterDivide, r) {
169cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = color.r / color.g; }", 1, 2, 0, 0, 0.5, 2, 0,
170cb93a386Sopenharmony_ci         0);
171cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color /= half4(1, 2, 3, 4); }", 12, 12, 12, 12, 12, 6,
172cb93a386Sopenharmony_ci         4, 3);
173cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { half4 c = color; color /= c; }", 4, 3, 2, 1,
174cb93a386Sopenharmony_ci         1, 1, 1, 1);
175cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = half(int(color.r) / int(color.g)); }", 8, -2, 0, 0,
176cb93a386Sopenharmony_ci         -4, -2, 0, 0);
177cb93a386Sopenharmony_ci}
178cb93a386Sopenharmony_ci
179cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterAnd, r) {
180cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r > color.g && color.g > color.b) "
181cb93a386Sopenharmony_ci            "color = half4(color.a); }", 2, 1, 0, 3, 3, 3, 3, 3);
182cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r > color.g && color.g > color.b) "
183cb93a386Sopenharmony_ci            "color = half4(color.a); }", 1, 1, 0, 3, 1, 1, 0, 3);
184cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r > color.g && color.g > color.b) "
185cb93a386Sopenharmony_ci            "color = half4(color.a); }", 2, 1, 1, 3, 2, 1, 1, 3);
186cb93a386Sopenharmony_ci    test(r, "half global; bool update() { global = 123; return true; }"
187cb93a386Sopenharmony_ci            "void main(inout half4 color) { global = 0;  if (color.r > color.g && update()) "
188cb93a386Sopenharmony_ci            "color = half4(color.a); color.a = global; }", 2, 1, 1, 3, 3, 3, 3, 123);
189cb93a386Sopenharmony_ci    test(r, "half global; bool update() { global = 123; return true; }"
190cb93a386Sopenharmony_ci            "void main(inout half4 color) { global = 0;  if (color.r > color.g && update()) "
191cb93a386Sopenharmony_ci            "color = half4(color.a); color.a = global; }", 1, 1, 1, 3, 1, 1, 1, 0);
192cb93a386Sopenharmony_ci}
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterOr, r) {
195cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r > color.g || color.g > color.b) "
196cb93a386Sopenharmony_ci            "color = half4(color.a); }", 2, 1, 0, 3, 3, 3, 3, 3);
197cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r > color.g || color.g > color.b) "
198cb93a386Sopenharmony_ci            "color = half4(color.a); }", 1, 1, 0, 3, 3, 3, 3, 3);
199cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r > color.g || color.g > color.b) "
200cb93a386Sopenharmony_ci            "color = half4(color.a); }", 1, 1, 1, 3, 1, 1, 1, 3);
201cb93a386Sopenharmony_ci    test(r, "half global; bool update() { global = 123; return true; }"
202cb93a386Sopenharmony_ci            "void main(inout half4 color) { global = 0;  if (color.r > color.g || update()) "
203cb93a386Sopenharmony_ci            "color = half4(color.a); color.a = global; }", 1, 1, 1, 3, 3, 3, 3, 123);
204cb93a386Sopenharmony_ci    test(r, "half global; bool update() { global = 123; return true; }"
205cb93a386Sopenharmony_ci            "void main(inout half4 color) { global = 0;  if (color.r > color.g || update()) "
206cb93a386Sopenharmony_ci            "color = half4(color.a); color.a = global; }", 2, 1, 1, 3, 3, 3, 3, 0);
207cb93a386Sopenharmony_ci}
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterMatrix, r) {
210cb93a386Sopenharmony_ci    float in[16];
211cb93a386Sopenharmony_ci    float expected[16];
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ci    // Constructing matrix from scalar produces a diagonal matrix
214cb93a386Sopenharmony_ci    in[0] = 2.0f;
215cb93a386Sopenharmony_ci    expected[0] = 4.0f;
216cb93a386Sopenharmony_ci    test(r, "float main(float x) { float4x4 m = float4x4(x); return m[1][1] + m[1][2] + m[2][2]; }",
217cb93a386Sopenharmony_ci         in, expected);
218cb93a386Sopenharmony_ci
219cb93a386Sopenharmony_ci    // Constructing from a different-sized matrix fills the remaining space with the identity matrix
220cb93a386Sopenharmony_ci    expected[0] = 3.0f;
221cb93a386Sopenharmony_ci    test(r, "float main(float x) {"
222cb93a386Sopenharmony_ci         "float2x2 m = float2x2(x);"
223cb93a386Sopenharmony_ci         "float4x4 m2 = float4x4(m);"
224cb93a386Sopenharmony_ci         "return m2[0][0] + m2[3][3]; }",
225cb93a386Sopenharmony_ci         in, expected);
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci    // Constructing a matrix from vectors or scalars fills in values in column-major order
228cb93a386Sopenharmony_ci    in[0] = 1.0f;
229cb93a386Sopenharmony_ci    in[1] = 2.0f;
230cb93a386Sopenharmony_ci    in[2] = 4.0f;
231cb93a386Sopenharmony_ci    in[3] = 8.0f;
232cb93a386Sopenharmony_ci    expected[0] = 6.0f;
233cb93a386Sopenharmony_ci    test(r, "float main(float4 v) { float2x2 m = float2x2(v); return m[0][1] + m[1][0]; }",
234cb93a386Sopenharmony_ci         in, expected);
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ci    expected[0] = 10.0f;
237cb93a386Sopenharmony_ci    test(r, "float main(float4 v) {"
238cb93a386Sopenharmony_ci         "float2x2 m = float2x2(v.x, v.y, v.w, v.z);"
239cb93a386Sopenharmony_ci         "return m[0][1] + m[1][0]; }",
240cb93a386Sopenharmony_ci         in, expected);
241cb93a386Sopenharmony_ci
242cb93a386Sopenharmony_ci    // Initialize 16 values to be used as inputs to matrix tests
243cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) { in[i] = (float)i; }
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci    // M+M, M-S, S-M
246cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) { expected[i] = (float)(2 * i); }
247cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return m + m; }", in, expected);
248cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) { expected[i] = (float)(i + 3); }
249cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return m + 3.0; }", in, expected);
250cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return 3.0 + m; }", in, expected);
251cb93a386Sopenharmony_ci
252cb93a386Sopenharmony_ci    // M-M, M-S, S-M
253cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) { expected[i] = 4.0f; }
254cb93a386Sopenharmony_ci    test(r, "float2x2 main(float2x2 m1, float2x2 m2) { return m2 - m1; }", in, expected);
255cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) { expected[i] = (float)(i - 3); }
256cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return m - 3.0; }", in, expected);
257cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) { expected[i] = (float)(3 - i); }
258cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return 3.0 - m; }", in, expected);
259cb93a386Sopenharmony_ci
260cb93a386Sopenharmony_ci    // M*S, S*M, M/S, S/M
261cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) { expected[i] = (float)(i * 3); }
262cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return m * 3.0; }", in, expected);
263cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return 3.0 * m; }", in, expected);
264cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) { expected[i] = (float)(i) / 2.0f; }
265cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return m / 2.0; }", in, expected);
266cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) { expected[i] = 1.0f / (float)(i + 1); }
267cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return 1.0 / (m + 1); }", in, expected);
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_ci    // Matrix negation
270cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) { expected[i] = (float)(-i); }
271cb93a386Sopenharmony_ci    test(r, "float4x4 main(float4x4 m) { return -m; }", in, expected);
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_ci    // M*V, V*M
274cb93a386Sopenharmony_ci    for (int i = 0; i < 3; ++i) {
275cb93a386Sopenharmony_ci        expected[i] = 9.0f*i + 10.0f*(i+3) + 11.0f*(i+6);
276cb93a386Sopenharmony_ci    }
277cb93a386Sopenharmony_ci    test(r, "float3 main(float3x3 m, float3 v) { return m * v; }", in, expected);
278cb93a386Sopenharmony_ci    for (int i = 0; i < 3; ++i) {
279cb93a386Sopenharmony_ci        expected[i] = 9.0f*(3*i) + 10.0f*(3*i+1) + 11.0f*(3*i+2);
280cb93a386Sopenharmony_ci    }
281cb93a386Sopenharmony_ci    test(r, "float3 main(float3x3 m, float3 v) { return v * m; }", in, expected);
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_ci    // M*M
284cb93a386Sopenharmony_ci    {
285cb93a386Sopenharmony_ci        SkM44 m = SkM44::ColMajor(in);
286cb93a386Sopenharmony_ci        SkM44 m2;
287cb93a386Sopenharmony_ci        float in2[16];
288cb93a386Sopenharmony_ci        for (int i = 0; i < 16; ++i) {
289cb93a386Sopenharmony_ci            in2[i] = (i + 4) % 16;
290cb93a386Sopenharmony_ci        }
291cb93a386Sopenharmony_ci        m2 = SkM44::ColMajor(in2);
292cb93a386Sopenharmony_ci        m.setConcat(m, m2);
293cb93a386Sopenharmony_ci        // Rearrange the columns on the RHS so we detect left-hand/right-hand errors
294cb93a386Sopenharmony_ci        test(r, "float4x4 main(float4x4 m) { return m * float4x4(m[1], m[2], m[3], m[0]); }",
295cb93a386Sopenharmony_ci             in, (float*)&m);
296cb93a386Sopenharmony_ci    }
297cb93a386Sopenharmony_ci}
298cb93a386Sopenharmony_ci
299cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterTernary, r) {
300cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = color.g > color.b ? color.g : color.b; }",
301cb93a386Sopenharmony_ci         0, 1, 2, 0, 2, 1, 2, 0);
302cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = color.g > color.b ? color.g : color.b; }",
303cb93a386Sopenharmony_ci         0, 3, 2, 0, 3, 3, 2, 0);
304cb93a386Sopenharmony_ci}
305cb93a386Sopenharmony_ci
306cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterCast, r) {
307cb93a386Sopenharmony_ci    union Val {
308cb93a386Sopenharmony_ci        float    f;
309cb93a386Sopenharmony_ci        int32_t  s;
310cb93a386Sopenharmony_ci    };
311cb93a386Sopenharmony_ci
312cb93a386Sopenharmony_ci    Val input[2];
313cb93a386Sopenharmony_ci    Val expected[2];
314cb93a386Sopenharmony_ci
315cb93a386Sopenharmony_ci    input[0].s = 3;
316cb93a386Sopenharmony_ci    input[1].s = -5;
317cb93a386Sopenharmony_ci    expected[0].f = 3.0f;
318cb93a386Sopenharmony_ci    expected[1].f = -5.0f;
319cb93a386Sopenharmony_ci    test(r, "float  main(int  x) { return float (x); }", (float*)input, (float*)expected);
320cb93a386Sopenharmony_ci    test(r, "float2 main(int2 x) { return float2(x); }", (float*)input, (float*)expected);
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_ci    input[0].f = 3.0f;
323cb93a386Sopenharmony_ci    input[1].f = -5.0f;
324cb93a386Sopenharmony_ci    expected[0].s = 3;
325cb93a386Sopenharmony_ci    expected[1].s = -5;
326cb93a386Sopenharmony_ci    test(r, "int  main(float  x) { return int (x); }", (float*)input, (float*)expected);
327cb93a386Sopenharmony_ci    test(r, "int2 main(float2 x) { return int2(x); }", (float*)input, (float*)expected);
328cb93a386Sopenharmony_ci
329cb93a386Sopenharmony_ci    input[0].s = 3;
330cb93a386Sopenharmony_ci    expected[0].f = 3.0f;
331cb93a386Sopenharmony_ci    expected[1].f = 3.0f;
332cb93a386Sopenharmony_ci    test(r, "float2 main(int x) { return float2(x); }", (float*)input, (float*)expected);
333cb93a386Sopenharmony_ci}
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterIf, r) {
336cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r > color.g) color.a = 1; }", 5, 3, 0, 0,
337cb93a386Sopenharmony_ci         5, 3, 0, 1);
338cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r > color.g) color.a = 1; }", 5, 5, 0, 0,
339cb93a386Sopenharmony_ci         5, 5, 0, 0);
340cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r > color.g) color.a = 1; }", 5, 6, 0, 0,
341cb93a386Sopenharmony_ci         5, 6, 0, 0);
342cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r < color.g) color.a = 1; }", 3, 5, 0, 0,
343cb93a386Sopenharmony_ci         3, 5, 0, 1);
344cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r < color.g) color.a = 1; }", 5, 5, 0, 0,
345cb93a386Sopenharmony_ci         5, 5, 0, 0);
346cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r < color.g) color.a = 1; }", 6, 5, 0, 0,
347cb93a386Sopenharmony_ci         6, 5, 0, 0);
348cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r >= color.g) color.a = 1; }", 5, 3, 0, 0,
349cb93a386Sopenharmony_ci         5, 3, 0, 1);
350cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r >= color.g) color.a = 1; }", 5, 5, 0, 0,
351cb93a386Sopenharmony_ci         5, 5, 0, 1);
352cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r >= color.g) color.a = 1; }", 5, 6, 0, 0,
353cb93a386Sopenharmony_ci         5, 6, 0, 0);
354cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r <= color.g) color.a = 1; }", 3, 5, 0, 0,
355cb93a386Sopenharmony_ci         3, 5, 0, 1);
356cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r <= color.g) color.a = 1; }", 5, 5, 0, 0,
357cb93a386Sopenharmony_ci         5, 5, 0, 1);
358cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r <= color.g) color.a = 1; }", 6, 5, 0, 0,
359cb93a386Sopenharmony_ci         6, 5, 0, 0);
360cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r == color.g) color.a = 1; }", 2, 2, 0, 0,
361cb93a386Sopenharmony_ci         2, 2, 0, 1);
362cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r == color.g) color.a = 1; }", 2, -2, 0, 0,
363cb93a386Sopenharmony_ci         2, -2, 0, 0);
364cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r != color.g) color.a = 1; }", 2, 2, 0, 0,
365cb93a386Sopenharmony_ci         2, 2, 0, 0);
366cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r != color.g) color.a = 1; }", 2, -2, 0, 0,
367cb93a386Sopenharmony_ci         2, -2, 0, 1);
368cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (!(color.r == color.g)) color.a = 1; }", 2, 2, 0, 0,
369cb93a386Sopenharmony_ci         2, 2, 0, 0);
370cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (!(color.r == color.g)) color.a = 1; }", 2, -2, 0, 0,
371cb93a386Sopenharmony_ci         2, -2, 0, 1);
372cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r == color.g) color.a = 1; else "
373cb93a386Sopenharmony_ci         "color.a = 2; }", 1, 1, 0, 0, 1, 1, 0, 1);
374cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.r == color.g) color.a = 1; else "
375cb93a386Sopenharmony_ci         "color.a = 2; }", 2, -2, 0, 0, 2, -2, 0, 2);
376cb93a386Sopenharmony_ci}
377cb93a386Sopenharmony_ci
378cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterIfVector, r) {
379cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.rg == color.ba) color.a = 1; }",
380cb93a386Sopenharmony_ci         1, 2, 1, 2, 1, 2, 1, 1);
381cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.rg == color.ba) color.a = 1; }",
382cb93a386Sopenharmony_ci         1, 2, 3, 2, 1, 2, 3, 2);
383cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.rg != color.ba) color.a = 1; }",
384cb93a386Sopenharmony_ci         1, 2, 1, 2, 1, 2, 1, 2);
385cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { if (color.rg != color.ba) color.a = 1; }",
386cb93a386Sopenharmony_ci         1, 2, 3, 2, 1, 2, 3, 1);
387cb93a386Sopenharmony_ci}
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterFor, r) {
390cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { for (int i = 1; i <= 10; ++i) color.r += half(i); }",
391cb93a386Sopenharmony_ci         0, 0, 0, 0,
392cb93a386Sopenharmony_ci         55, 0, 0, 0);
393cb93a386Sopenharmony_ci    test(r,
394cb93a386Sopenharmony_ci         "void main(inout half4 color) {"
395cb93a386Sopenharmony_ci         "    for (int i = 1; i <= 10; ++i)"
396cb93a386Sopenharmony_ci         "        for (int j = 1; j <= 10; ++j)"
397cb93a386Sopenharmony_ci         "            if (j >= i) { color.r += half(j); }"
398cb93a386Sopenharmony_ci         "}",
399cb93a386Sopenharmony_ci         0, 0, 0, 0,
400cb93a386Sopenharmony_ci         385, 0, 0, 0);
401cb93a386Sopenharmony_ci    test(r,
402cb93a386Sopenharmony_ci         "void main(inout half4 color) {"
403cb93a386Sopenharmony_ci         "    for (int i = 1; i <= 10; ++i)"
404cb93a386Sopenharmony_ci         "        for (int j = 1; j < 20 ; ++j) {"
405cb93a386Sopenharmony_ci         "            if (i == j) continue;"
406cb93a386Sopenharmony_ci         "            if (j > 10) break;"
407cb93a386Sopenharmony_ci         "            color.r += half(j);"
408cb93a386Sopenharmony_ci         "        }"
409cb93a386Sopenharmony_ci         "}",
410cb93a386Sopenharmony_ci         0, 0, 0, 0,
411cb93a386Sopenharmony_ci         495, 0, 0, 0);
412cb93a386Sopenharmony_ci}
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterPrefixPostfix, r) {
415cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = ++color.g; }", 1, 2, 3, 4, 3, 3, 3, 4);
416cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.r = color.g++; }", 1, 2, 3, 4, 2, 3, 3, 4);
417cb93a386Sopenharmony_ci}
418cb93a386Sopenharmony_ci
419cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterSwizzle, r) {
420cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color = color.abgr; }", 1, 2, 3, 4, 4, 3, 2, 1);
421cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.rgb = half4(5, 6, 7, 8).bbg; }", 1, 2, 3, 4, 7, 7,
422cb93a386Sopenharmony_ci         6, 4);
423cb93a386Sopenharmony_ci    test(r, "void main(inout half4 color) { color.bgr = half3(5, 6, 7); }", 1, 2, 3, 4, 7, 6,
424cb93a386Sopenharmony_ci         5, 4);
425cb93a386Sopenharmony_ci}
426cb93a386Sopenharmony_ci
427cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterGlobal, r) {
428cb93a386Sopenharmony_ci    test(r, "int x; void main(inout half4 color) { x = 10; color.b = half(x); }", 1, 2, 3, 4, 1, 2,
429cb93a386Sopenharmony_ci         10, 4);
430cb93a386Sopenharmony_ci    test(r, "float4 x; void main(inout float4 color) { x = color * 2; color = x; }",
431cb93a386Sopenharmony_ci         1, 2, 3, 4, 2, 4, 6, 8);
432cb93a386Sopenharmony_ci    test(r, "float4 x; void main(inout float4 color) { x = float4(5, 6, 7, 8); color = x.wzyx; }",
433cb93a386Sopenharmony_ci         1, 2, 3, 4, 8, 7, 6, 5);
434cb93a386Sopenharmony_ci    test(r, "float4 x; void main(inout float4 color) { x.wzyx = float4(5, 6, 7, 8); color = x; }",
435cb93a386Sopenharmony_ci         1, 2, 3, 4, 8, 7, 6, 5);
436cb93a386Sopenharmony_ci}
437cb93a386Sopenharmony_ci
438cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterGeneric, r) {
439cb93a386Sopenharmony_ci    float value1 = 5;
440cb93a386Sopenharmony_ci    float expected1 = 25;
441cb93a386Sopenharmony_ci    test(r, "float main(float x) { return x * x; }", &value1, &expected1);
442cb93a386Sopenharmony_ci    float value2[2] = { 5, 25 };
443cb93a386Sopenharmony_ci    float expected2[2] = { 25, 625 };
444cb93a386Sopenharmony_ci    test(r, "float2 main(float x, float y) { return float2(x * x, y * y); }", value2, expected2);
445cb93a386Sopenharmony_ci}
446cb93a386Sopenharmony_ci
447cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterFieldAccessComplex, r) {
448cb93a386Sopenharmony_ci    const char* src = R"(
449cb93a386Sopenharmony_ci        struct P { float x; float y; };
450cb93a386Sopenharmony_ci        P make_point() { P p; p.x = 7; p.y = 3; return p; }
451cb93a386Sopenharmony_ci        float main() { return make_point().y; }
452cb93a386Sopenharmony_ci    )";
453cb93a386Sopenharmony_ci
454cb93a386Sopenharmony_ci    float expected = 3.0f;
455cb93a386Sopenharmony_ci    test(r, src, /*in=*/nullptr, &expected);
456cb93a386Sopenharmony_ci}
457cb93a386Sopenharmony_ci
458cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterIndexComplex, r) {
459cb93a386Sopenharmony_ci    const char* src = R"(
460cb93a386Sopenharmony_ci        float2x2 make_mtx() { return float2x2(1, 2, 3, 4); }
461cb93a386Sopenharmony_ci        float main() { return make_mtx()[1][0]; }
462cb93a386Sopenharmony_ci    )";
463cb93a386Sopenharmony_ci
464cb93a386Sopenharmony_ci    float expected = 3.0f;
465cb93a386Sopenharmony_ci    test(r, src, /*in=*/nullptr, &expected);
466cb93a386Sopenharmony_ci}
467cb93a386Sopenharmony_ci
468cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterCompound, r) {
469cb93a386Sopenharmony_ci    struct RectAndColor { SkIRect fRect; SkColor4f fColor; };
470cb93a386Sopenharmony_ci    struct ManyRects { int fNumRects; RectAndColor fRects[4]; };
471cb93a386Sopenharmony_ci
472cb93a386Sopenharmony_ci    const char* src =
473cb93a386Sopenharmony_ci        // Some struct definitions
474cb93a386Sopenharmony_ci        "struct Point { int x; int y; };\n"
475cb93a386Sopenharmony_ci        "struct Rect {  Point p0; Point p1; };\n"
476cb93a386Sopenharmony_ci        "struct RectAndColor { Rect r; float4 color; };\n"
477cb93a386Sopenharmony_ci
478cb93a386Sopenharmony_ci        // Structs as globals, parameters, return values
479cb93a386Sopenharmony_ci        "RectAndColor temp;\n"
480cb93a386Sopenharmony_ci        "int rect_height(Rect r) { return r.p1.y - r.p0.y; }\n"
481cb93a386Sopenharmony_ci        "RectAndColor make_blue_rect(int w, int h) {\n"
482cb93a386Sopenharmony_ci        "  temp.r.p0.x = temp.r.p0.y = 0;\n"
483cb93a386Sopenharmony_ci        "  temp.r.p1.x = w; temp.r.p1.y = h;\n"
484cb93a386Sopenharmony_ci        "  temp.color = float4(0, 1, 0, 1);\n"
485cb93a386Sopenharmony_ci        "  return temp;\n"
486cb93a386Sopenharmony_ci        "}\n"
487cb93a386Sopenharmony_ci
488cb93a386Sopenharmony_ci        // Initialization and assignment of types larger than 4 slots
489cb93a386Sopenharmony_ci        "RectAndColor init_big(RectAndColor r) { RectAndColor s = r; return s; }\n"
490cb93a386Sopenharmony_ci        "RectAndColor copy_big(RectAndColor r) { RectAndColor s; s = r; return s; }\n"
491cb93a386Sopenharmony_ci
492cb93a386Sopenharmony_ci        // Same for arrays, including some non-constant indexing
493cb93a386Sopenharmony_ci        "int median(int a[15]) { return a[7]; }\n"
494cb93a386Sopenharmony_ci
495cb93a386Sopenharmony_ci        "float tempFloats[8];\n"
496cb93a386Sopenharmony_ci        "float sums(float a[8]) {\n"
497cb93a386Sopenharmony_ci        "  tempFloats[0] = a[0];\n"
498cb93a386Sopenharmony_ci        "  for (int i = 1; i < 8; ++i) { tempFloats[i] = tempFloats[i - 1] + a[i]; }\n"
499cb93a386Sopenharmony_ci        "  return tempFloats[7];\n"
500cb93a386Sopenharmony_ci        "}\n"
501cb93a386Sopenharmony_ci
502cb93a386Sopenharmony_ci        // Uniforms, array-of-structs
503cb93a386Sopenharmony_ci        "uniform Rect gRects[4];\n"
504cb93a386Sopenharmony_ci        "Rect get_rect_2() { return gRects[2]; }\n"
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_ci        // Kitchen sink (swizzles, inout, SoAoS)
507cb93a386Sopenharmony_ci        "struct ManyRects { int numRects; RectAndColor rects[4]; };\n"
508cb93a386Sopenharmony_ci        "void fill_rects(inout ManyRects mr) {\n"
509cb93a386Sopenharmony_ci        "  for (int i = 0; i < 4; ++i) {\n"
510cb93a386Sopenharmony_ci        "    if (i >= mr.numRects) { break; }\n"
511cb93a386Sopenharmony_ci        "    mr.rects[i].r = gRects[i];\n"
512cb93a386Sopenharmony_ci        "    float b = float(mr.rects[i].r.p1.y);\n"
513cb93a386Sopenharmony_ci        "    mr.rects[i].color = float4(b, b, b, b);\n"
514cb93a386Sopenharmony_ci        "  }\n"
515cb93a386Sopenharmony_ci        "}\n";
516cb93a386Sopenharmony_ci
517cb93a386Sopenharmony_ci    ProgramBuilder program(r, src);
518cb93a386Sopenharmony_ci
519cb93a386Sopenharmony_ci    auto rect_height    = SkSL::Program_GetFunction(*program, "rect_height"),
520cb93a386Sopenharmony_ci         make_blue_rect = SkSL::Program_GetFunction(*program, "make_blue_rect"),
521cb93a386Sopenharmony_ci         median         = SkSL::Program_GetFunction(*program, "median"),
522cb93a386Sopenharmony_ci         sums           = SkSL::Program_GetFunction(*program, "sums"),
523cb93a386Sopenharmony_ci         get_rect_2     = SkSL::Program_GetFunction(*program, "get_rect_2"),
524cb93a386Sopenharmony_ci         fill_rects     = SkSL::Program_GetFunction(*program, "fill_rects");
525cb93a386Sopenharmony_ci
526cb93a386Sopenharmony_ci    SkIRect gRects[4] = { { 1,2,3,4 }, { 5,6,7,8 }, { 9,10,11,12 }, { 13,14,15,16 } };
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ci    auto build = [&](const SkSL::FunctionDefinition* fn) {
529cb93a386Sopenharmony_ci        skvm::Builder b;
530cb93a386Sopenharmony_ci        skvm::UPtr uniformPtr = b.uniform();
531cb93a386Sopenharmony_ci        skvm::Val uniforms[16];
532cb93a386Sopenharmony_ci        for (int i = 0; i < 16; ++i) {
533cb93a386Sopenharmony_ci            uniforms[i] = b.uniform32(uniformPtr, i * sizeof(int)).id;
534cb93a386Sopenharmony_ci        }
535cb93a386Sopenharmony_ci        SkSL::ProgramToSkVM(*program, *fn, &b, /*debugInfo=*/nullptr, SkMakeSpan(uniforms));
536cb93a386Sopenharmony_ci        return b.done();
537cb93a386Sopenharmony_ci    };
538cb93a386Sopenharmony_ci
539cb93a386Sopenharmony_ci    struct Args {
540cb93a386Sopenharmony_ci        Args(void* uniformData) { fArgs.push_back(uniformData); }
541cb93a386Sopenharmony_ci        void add(void* base, int n) {
542cb93a386Sopenharmony_ci            for (int i = 0; i < n; ++i) {
543cb93a386Sopenharmony_ci                fArgs.push_back(SkTAddOffset<void>(base, i * sizeof(float)));
544cb93a386Sopenharmony_ci            }
545cb93a386Sopenharmony_ci        }
546cb93a386Sopenharmony_ci        std::vector<void*> fArgs;
547cb93a386Sopenharmony_ci    };
548cb93a386Sopenharmony_ci
549cb93a386Sopenharmony_ci    {
550cb93a386Sopenharmony_ci        SkIRect in = SkIRect::MakeXYWH(10, 10, 20, 30);
551cb93a386Sopenharmony_ci        int out = 0;
552cb93a386Sopenharmony_ci        skvm::Program p = build(rect_height);
553cb93a386Sopenharmony_ci        Args args(gRects);
554cb93a386Sopenharmony_ci        args.add(&in, 4);
555cb93a386Sopenharmony_ci        args.add(&out, 1);
556cb93a386Sopenharmony_ci        p.eval(1, args.fArgs.data());
557cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, out == 30);
558cb93a386Sopenharmony_ci    }
559cb93a386Sopenharmony_ci
560cb93a386Sopenharmony_ci    {
561cb93a386Sopenharmony_ci        int in[2] = { 15, 25 };
562cb93a386Sopenharmony_ci        RectAndColor out;
563cb93a386Sopenharmony_ci        skvm::Program p = build(make_blue_rect);
564cb93a386Sopenharmony_ci        Args args(gRects);
565cb93a386Sopenharmony_ci        args.add(&in, 2);
566cb93a386Sopenharmony_ci        args.add(&out, 8);
567cb93a386Sopenharmony_ci        p.eval(1, args.fArgs.data());
568cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, out.fRect.width() == 15);
569cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, out.fRect.height() == 25);
570cb93a386Sopenharmony_ci        SkColor4f blue = { 0.0f, 1.0f, 0.0f, 1.0f };
571cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, out.fColor == blue);
572cb93a386Sopenharmony_ci    }
573cb93a386Sopenharmony_ci
574cb93a386Sopenharmony_ci    {
575cb93a386Sopenharmony_ci        int in[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
576cb93a386Sopenharmony_ci        int out = 0;
577cb93a386Sopenharmony_ci        skvm::Program p = build(median);
578cb93a386Sopenharmony_ci        Args args(gRects);
579cb93a386Sopenharmony_ci        args.add(&in, 15);
580cb93a386Sopenharmony_ci        args.add(&out, 1);
581cb93a386Sopenharmony_ci        p.eval(1, args.fArgs.data());
582cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, out == 8);
583cb93a386Sopenharmony_ci    }
584cb93a386Sopenharmony_ci
585cb93a386Sopenharmony_ci    {
586cb93a386Sopenharmony_ci        float in[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
587cb93a386Sopenharmony_ci        float out = 0;
588cb93a386Sopenharmony_ci        skvm::Program p = build(sums);
589cb93a386Sopenharmony_ci        Args args(gRects);
590cb93a386Sopenharmony_ci        args.add(&in, 8);
591cb93a386Sopenharmony_ci        args.add(&out, 1);
592cb93a386Sopenharmony_ci        p.eval(1, args.fArgs.data());
593cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, out == static_cast<float>((7 + 1) * (7 + 2) / 2));
594cb93a386Sopenharmony_ci    }
595cb93a386Sopenharmony_ci
596cb93a386Sopenharmony_ci    {
597cb93a386Sopenharmony_ci        SkIRect out = SkIRect::MakeEmpty();
598cb93a386Sopenharmony_ci        skvm::Program p = build(get_rect_2);
599cb93a386Sopenharmony_ci        Args args(gRects);
600cb93a386Sopenharmony_ci        args.add(&out, 4);
601cb93a386Sopenharmony_ci        p.eval(1, args.fArgs.data());
602cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, out == gRects[2]);
603cb93a386Sopenharmony_ci    }
604cb93a386Sopenharmony_ci
605cb93a386Sopenharmony_ci    {
606cb93a386Sopenharmony_ci        ManyRects in;
607cb93a386Sopenharmony_ci        memset(&in, 0, sizeof(in));
608cb93a386Sopenharmony_ci        in.fNumRects = 2;
609cb93a386Sopenharmony_ci        skvm::Program p = build(fill_rects);
610cb93a386Sopenharmony_ci        Args args(gRects);
611cb93a386Sopenharmony_ci        args.add(&in, 33);
612cb93a386Sopenharmony_ci        p.eval(1, args.fArgs.data());
613cb93a386Sopenharmony_ci        ManyRects expected;
614cb93a386Sopenharmony_ci        memset(&expected, 0, sizeof(expected));
615cb93a386Sopenharmony_ci        expected.fNumRects = 2;
616cb93a386Sopenharmony_ci        for (int i = 0; i < 2; ++i) {
617cb93a386Sopenharmony_ci            expected.fRects[i].fRect = gRects[i];
618cb93a386Sopenharmony_ci            float c = gRects[i].fBottom;
619cb93a386Sopenharmony_ci            expected.fRects[i].fColor = { c, c, c, c };
620cb93a386Sopenharmony_ci        }
621cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, memcmp(&in, &expected, sizeof(in)) == 0);
622cb93a386Sopenharmony_ci    }
623cb93a386Sopenharmony_ci}
624cb93a386Sopenharmony_ci
625cb93a386Sopenharmony_cistatic void expect_failure(skiatest::Reporter* r, const char* src) {
626cb93a386Sopenharmony_ci    GrShaderCaps caps;
627cb93a386Sopenharmony_ci    SkSL::Compiler compiler(&caps);
628cb93a386Sopenharmony_ci    SkSL::Program::Settings settings;
629cb93a386Sopenharmony_ci    auto program = compiler.convertProgram(SkSL::ProgramKind::kGeneric,
630cb93a386Sopenharmony_ci                                           SkSL::String(src), settings);
631cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !program);
632cb93a386Sopenharmony_ci}
633cb93a386Sopenharmony_ci
634cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterRestrictLoops, r) {
635cb93a386Sopenharmony_ci    // while and do-while loops are not allowed
636cb93a386Sopenharmony_ci    expect_failure(r, "void main(inout float x) { while (x < 1) { x++; } }");
637cb93a386Sopenharmony_ci    expect_failure(r, "void main(inout float x) { do { x++; } while (x < 1); }");
638cb93a386Sopenharmony_ci}
639cb93a386Sopenharmony_ci
640cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterReturnThenCall, r) {
641cb93a386Sopenharmony_ci    // Test that early returns disable execution in subsequently called functions
642cb93a386Sopenharmony_ci    const char* src = R"(
643cb93a386Sopenharmony_ci        float y;
644cb93a386Sopenharmony_ci        void inc () { ++y; }
645cb93a386Sopenharmony_ci        void maybe_inc() { if (y < 0) return; inc(); }
646cb93a386Sopenharmony_ci        void main(inout float x) { y = x; maybe_inc(); x = y; }
647cb93a386Sopenharmony_ci    )";
648cb93a386Sopenharmony_ci
649cb93a386Sopenharmony_ci    ProgramBuilder program(r, src);
650cb93a386Sopenharmony_ci    const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
651cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, main);
652cb93a386Sopenharmony_ci
653cb93a386Sopenharmony_ci    skvm::Builder b;
654cb93a386Sopenharmony_ci    SkSL::ProgramToSkVM(*program, *main, &b, /*debugInfo=*/nullptr, /*uniforms=*/{});
655cb93a386Sopenharmony_ci    skvm::Program p = b.done();
656cb93a386Sopenharmony_ci
657cb93a386Sopenharmony_ci    float xs[] = { -2.0f, 0.0f, 3.0f, -1.0f };
658cb93a386Sopenharmony_ci    p.eval(4, xs);
659cb93a386Sopenharmony_ci
660cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, xs[0] == -2.0f);
661cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, xs[1] ==  1.0f);
662cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, xs[2] ==  4.0f);
663cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, xs[3] == -1.0f);
664cb93a386Sopenharmony_ci}
665cb93a386Sopenharmony_ci
666cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterEarlyReturn, r) {
667cb93a386Sopenharmony_ci    // Test early returns with divergent control flow
668cb93a386Sopenharmony_ci    const char* src = "float main(float x, float y) { if (x < y) { return x; } return y; }";
669cb93a386Sopenharmony_ci
670cb93a386Sopenharmony_ci    ProgramBuilder program(r, src);
671cb93a386Sopenharmony_ci
672cb93a386Sopenharmony_ci    const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
673cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, main);
674cb93a386Sopenharmony_ci
675cb93a386Sopenharmony_ci    skvm::Builder b;
676cb93a386Sopenharmony_ci    SkSL::ProgramToSkVM(*program, *main, &b, /*debugInfo=*/nullptr, /*uniforms=*/{});
677cb93a386Sopenharmony_ci    skvm::Program p = b.done();
678cb93a386Sopenharmony_ci
679cb93a386Sopenharmony_ci    float xs[] = { 1.0f, 3.0f },
680cb93a386Sopenharmony_ci          ys[] = { 2.0f, 2.0f };
681cb93a386Sopenharmony_ci    float rets[2];
682cb93a386Sopenharmony_ci    p.eval(2, xs, ys, rets);
683cb93a386Sopenharmony_ci
684cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, rets[0] == 1.0f);
685cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, rets[1] == 2.0f);
686cb93a386Sopenharmony_ci}
687cb93a386Sopenharmony_ci
688cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterFunctions, r) {
689cb93a386Sopenharmony_ci    const char* src =
690cb93a386Sopenharmony_ci        "float sqr(float x) { return x * x; }\n"
691cb93a386Sopenharmony_ci        "float sub(float x, float y) { return x - y; }\n"
692cb93a386Sopenharmony_ci        "float main(float x) { return sub(sqr(x), x); }\n"
693cb93a386Sopenharmony_ci
694cb93a386Sopenharmony_ci        // Different signatures
695cb93a386Sopenharmony_ci        "float dot(float2 a, float2 b) { return a.x*b.x + a.y*b.y; }\n"
696cb93a386Sopenharmony_ci        "float dot(float3 a, float3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; }\n"
697cb93a386Sopenharmony_ci        "float dot3_test(float x) { return dot(float3(x, x + 1, x + 2), float3(1, -1, 2)); }\n"
698cb93a386Sopenharmony_ci        "float dot2_test(float x) { return dot(float2(x, x + 1), float2(1, -1)); }\n";
699cb93a386Sopenharmony_ci
700cb93a386Sopenharmony_ci    ProgramBuilder program(r, src);
701cb93a386Sopenharmony_ci
702cb93a386Sopenharmony_ci    auto sub  = SkSL::Program_GetFunction(*program, "sub");
703cb93a386Sopenharmony_ci    auto sqr  = SkSL::Program_GetFunction(*program, "sqr");
704cb93a386Sopenharmony_ci    auto main = SkSL::Program_GetFunction(*program, "main");
705cb93a386Sopenharmony_ci    auto tan  = SkSL::Program_GetFunction(*program, "tan");
706cb93a386Sopenharmony_ci    auto dot3 = SkSL::Program_GetFunction(*program, "dot3_test");
707cb93a386Sopenharmony_ci    auto dot2 = SkSL::Program_GetFunction(*program, "dot2_test");
708cb93a386Sopenharmony_ci
709cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, sub);
710cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, sqr);
711cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, main);
712cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, !tan);  // Getting a non-existent function should return nullptr
713cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, dot3);
714cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, dot2);
715cb93a386Sopenharmony_ci
716cb93a386Sopenharmony_ci    auto test_fn = [&](const SkSL::FunctionDefinition* fn, float in, float expected) {
717cb93a386Sopenharmony_ci        skvm::Builder b;
718cb93a386Sopenharmony_ci        SkSL::ProgramToSkVM(*program, *fn, &b, /*debugInfo=*/nullptr, /*uniforms=*/{});
719cb93a386Sopenharmony_ci        skvm::Program p = b.done();
720cb93a386Sopenharmony_ci
721cb93a386Sopenharmony_ci        float out = 0.0f;
722cb93a386Sopenharmony_ci        p.eval(1, &in, &out);
723cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, out == expected);
724cb93a386Sopenharmony_ci    };
725cb93a386Sopenharmony_ci
726cb93a386Sopenharmony_ci    test_fn(main, 3.0f, 6.0f);
727cb93a386Sopenharmony_ci    test_fn(dot3, 3.0f, 9.0f);
728cb93a386Sopenharmony_ci    test_fn(dot2, 3.0f, -1.0f);
729cb93a386Sopenharmony_ci}
730cb93a386Sopenharmony_ci
731cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterOutParams, r) {
732cb93a386Sopenharmony_ci    test(r,
733cb93a386Sopenharmony_ci         "void oneAlpha(inout half4 color) { color.a = 1; }"
734cb93a386Sopenharmony_ci         "void main(inout half4 color) { oneAlpha(color); }",
735cb93a386Sopenharmony_ci         0, 0, 0, 0, 0, 0, 0, 1);
736cb93a386Sopenharmony_ci    test(r,
737cb93a386Sopenharmony_ci         "half2 tricky(half x, half y, inout half2 color, half z) {"
738cb93a386Sopenharmony_ci         "    color.xy = color.yx;"
739cb93a386Sopenharmony_ci         "    return half2(x + y, z);"
740cb93a386Sopenharmony_ci         "}"
741cb93a386Sopenharmony_ci         "void main(inout half4 color) {"
742cb93a386Sopenharmony_ci         "    half2 t = tricky(1, 2, color.rb, 5);"
743cb93a386Sopenharmony_ci         "    color.ga = t;"
744cb93a386Sopenharmony_ci         "}",
745cb93a386Sopenharmony_ci         1, 2, 3, 4, 3, 3, 1, 5);
746cb93a386Sopenharmony_ci}
747cb93a386Sopenharmony_ci
748cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterSwizzleSingleLvalue, r) {
749cb93a386Sopenharmony_ci    test(r,
750cb93a386Sopenharmony_ci         "void main(inout half4 color) { color.xywz = half4(1,2,3,4); }",
751cb93a386Sopenharmony_ci         0, 0, 0, 0, 1, 2, 4, 3);
752cb93a386Sopenharmony_ci}
753cb93a386Sopenharmony_ci
754cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterSwizzleDoubleLvalue, r) {
755cb93a386Sopenharmony_ci    test(r,
756cb93a386Sopenharmony_ci         "void main(inout half4 color) { color.xywz.yxzw = half4(1,2,3,4); }",
757cb93a386Sopenharmony_ci         0, 0, 0, 0, 2, 1, 4, 3);
758cb93a386Sopenharmony_ci}
759cb93a386Sopenharmony_ci
760cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterSwizzleIndexLvalue, r) {
761cb93a386Sopenharmony_ci    const char* src = R"(
762cb93a386Sopenharmony_ci        void main(inout half4 color) {
763cb93a386Sopenharmony_ci            for (int i = 0; i < 4; i++) {
764cb93a386Sopenharmony_ci                color.wzyx[i] += half(i);
765cb93a386Sopenharmony_ci            }
766cb93a386Sopenharmony_ci        }
767cb93a386Sopenharmony_ci    )";
768cb93a386Sopenharmony_ci    test(r, src, 0, 0, 0, 0, 3, 2, 1, 0);
769cb93a386Sopenharmony_ci}
770cb93a386Sopenharmony_ci
771cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterMathFunctions, r) {
772cb93a386Sopenharmony_ci    float value[4], expected[4];
773cb93a386Sopenharmony_ci
774cb93a386Sopenharmony_ci    value[0] = 0.0f; expected[0] = 0.0f;
775cb93a386Sopenharmony_ci    test(r, "float main(float x) { return sin(x); }", value, expected);
776cb93a386Sopenharmony_ci    test(r, "float main(float x) { return tan(x); }", value, expected);
777cb93a386Sopenharmony_ci
778cb93a386Sopenharmony_ci    value[0] = 0.0f; expected[0] = 1.0f;
779cb93a386Sopenharmony_ci    test(r, "float main(float x) { return cos(x); }", value, expected);
780cb93a386Sopenharmony_ci
781cb93a386Sopenharmony_ci    value[0] = 25.0f; expected[0] = 5.0f;
782cb93a386Sopenharmony_ci    test(r, "float main(float x) { return sqrt(x); }", value, expected);
783cb93a386Sopenharmony_ci
784cb93a386Sopenharmony_ci    value[0] = 90.0f; expected[0] = sk_float_degrees_to_radians(value[0]);
785cb93a386Sopenharmony_ci    test(r, "float main(float x) { return radians(x); }", value, expected);
786cb93a386Sopenharmony_ci
787cb93a386Sopenharmony_ci    value[0] = 1.0f; value[1] = -1.0f;
788cb93a386Sopenharmony_ci    expected[0] = 1.0f / SK_FloatSqrt2; expected[1] = -1.0f / SK_FloatSqrt2;
789cb93a386Sopenharmony_ci    test(r, "float2 main(float2 x) { return normalize(x); }", value, expected);
790cb93a386Sopenharmony_ci}
791cb93a386Sopenharmony_ci
792cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterVoidFunction, r) {
793cb93a386Sopenharmony_ci    test(r,
794cb93a386Sopenharmony_ci         "half x; void foo() { x = 1.0; }"
795cb93a386Sopenharmony_ci         "void main(inout half4 color) { foo(); color.r = x; }",
796cb93a386Sopenharmony_ci         0, 0, 0, 0, 1, 0, 0, 0);
797cb93a386Sopenharmony_ci}
798cb93a386Sopenharmony_ci
799cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterMix, r) {
800cb93a386Sopenharmony_ci    float value, expected;
801cb93a386Sopenharmony_ci
802cb93a386Sopenharmony_ci    value = 0.5f; expected = 0.0f;
803cb93a386Sopenharmony_ci    test(r, "float main(float x) { return mix(-10, 10, x); }", &value, &expected);
804cb93a386Sopenharmony_ci    value = 0.75f; expected = 5.0f;
805cb93a386Sopenharmony_ci    test(r, "float main(float x) { return mix(-10, 10, x); }", &value, &expected);
806cb93a386Sopenharmony_ci    value = 2.0f; expected = 30.0f;
807cb93a386Sopenharmony_ci    test(r, "float main(float x) { return mix(-10, 10, x); }", &value, &expected);
808cb93a386Sopenharmony_ci
809cb93a386Sopenharmony_ci    float valueVectors[]   = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f },
810cb93a386Sopenharmony_ci          expectedVector[] = { 3.0f, 4.0f, 5.0f, 6.0f };
811cb93a386Sopenharmony_ci    test(r, "float4 main(float4 x, float4 y) { return mix(x, y, 0.5); }", valueVectors,
812cb93a386Sopenharmony_ci         expectedVector);
813cb93a386Sopenharmony_ci}
814cb93a386Sopenharmony_ci
815cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterCross, r) {
816cb93a386Sopenharmony_ci    float args[] = { 1.0f, 4.0f, -6.0f, -2.0f, 7.0f, -3.0f };
817cb93a386Sopenharmony_ci    SkV3 cross = SkV3::Cross({args[0], args[1], args[2]},
818cb93a386Sopenharmony_ci                             {args[3], args[4], args[5]});
819cb93a386Sopenharmony_ci    float expected[] = { cross.x, cross.y, cross.z };
820cb93a386Sopenharmony_ci    test(r, "float3 main(float3 x, float3 y) { return cross(x, y); }", args, expected);
821cb93a386Sopenharmony_ci}
822cb93a386Sopenharmony_ci
823cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterInverse, r) {
824cb93a386Sopenharmony_ci    {
825cb93a386Sopenharmony_ci        SkMatrix m;
826cb93a386Sopenharmony_ci        m.setRotate(30).postScale(1, 2);
827cb93a386Sopenharmony_ci        float args[4] = { m[0], m[3], m[1], m[4] };
828cb93a386Sopenharmony_ci        SkAssertResult(m.invert(&m));
829cb93a386Sopenharmony_ci        float expt[4] = { m[0], m[3], m[1], m[4] };
830cb93a386Sopenharmony_ci        test(r, "float2x2 main(float2x2 m) { return inverse(m); }", args, expt, false);
831cb93a386Sopenharmony_ci    }
832cb93a386Sopenharmony_ci    {
833cb93a386Sopenharmony_ci        SkMatrix m;
834cb93a386Sopenharmony_ci        m.setRotate(30).postScale(1, 2).postTranslate(1, 2);
835cb93a386Sopenharmony_ci        float args[9] = { m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8] };
836cb93a386Sopenharmony_ci        SkAssertResult(m.invert(&m));
837cb93a386Sopenharmony_ci        float expt[9] = { m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8] };
838cb93a386Sopenharmony_ci        test(r, "float3x3 main(float3x3 m) { return inverse(m); }", args, expt, false);
839cb93a386Sopenharmony_ci    }
840cb93a386Sopenharmony_ci    {
841cb93a386Sopenharmony_ci        float args[16], expt[16];
842cb93a386Sopenharmony_ci        // just some crazy thing that is invertible
843cb93a386Sopenharmony_ci        SkM44 m = {1, 2, 3, 4, 1, 2, 0, 3, 1, 0, 1, 4, 1, 3, 2, 0};
844cb93a386Sopenharmony_ci        m.getColMajor(args);
845cb93a386Sopenharmony_ci        SkAssertResult(m.invert(&m));
846cb93a386Sopenharmony_ci        m.getColMajor(expt);
847cb93a386Sopenharmony_ci        test(r, "float4x4 main(float4x4 m) { return inverse(m); }", args, expt, false);
848cb93a386Sopenharmony_ci    }
849cb93a386Sopenharmony_ci}
850cb93a386Sopenharmony_ci
851cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterDot, r) {
852cb93a386Sopenharmony_ci    float args[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };
853cb93a386Sopenharmony_ci    float expected = args[0] * args[2] +
854cb93a386Sopenharmony_ci                     args[1] * args[3];
855cb93a386Sopenharmony_ci    test(r, "float main(float2 x, float2 y) { return dot(x, y); }", args, &expected);
856cb93a386Sopenharmony_ci
857cb93a386Sopenharmony_ci    expected = args[0] * args[3] +
858cb93a386Sopenharmony_ci               args[1] * args[4] +
859cb93a386Sopenharmony_ci               args[2] * args[5];
860cb93a386Sopenharmony_ci    test(r, "float main(float3 x, float3 y) { return dot(x, y); }", args, &expected);
861cb93a386Sopenharmony_ci
862cb93a386Sopenharmony_ci    expected = args[0] * args[4] +
863cb93a386Sopenharmony_ci               args[1] * args[5] +
864cb93a386Sopenharmony_ci               args[2] * args[6] +
865cb93a386Sopenharmony_ci               args[3] * args[7];
866cb93a386Sopenharmony_ci    test(r, "float main(float4 x, float4 y) { return dot(x, y); }", args, &expected);
867cb93a386Sopenharmony_ci}
868cb93a386Sopenharmony_ci
869cb93a386Sopenharmony_ciclass ExternalSqrt : public SkSL::ExternalFunction {
870cb93a386Sopenharmony_cipublic:
871cb93a386Sopenharmony_ci    ExternalSqrt(const char* name, SkSL::Compiler& compiler)
872cb93a386Sopenharmony_ci        : INHERITED(name, *compiler.context().fTypes.fFloat)
873cb93a386Sopenharmony_ci        , fCompiler(compiler) {}
874cb93a386Sopenharmony_ci
875cb93a386Sopenharmony_ci    int callParameterCount() const override { return 1; }
876cb93a386Sopenharmony_ci
877cb93a386Sopenharmony_ci    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
878cb93a386Sopenharmony_ci        outTypes[0] = fCompiler.context().fTypes.fFloat.get();
879cb93a386Sopenharmony_ci    }
880cb93a386Sopenharmony_ci
881cb93a386Sopenharmony_ci    void call(skvm::Builder* b,
882cb93a386Sopenharmony_ci              skvm::F32* arguments,
883cb93a386Sopenharmony_ci              skvm::F32* outResult,
884cb93a386Sopenharmony_ci              skvm::I32 mask) const override {
885cb93a386Sopenharmony_ci        outResult[0] = sqrt(arguments[0]);
886cb93a386Sopenharmony_ci    }
887cb93a386Sopenharmony_ci
888cb93a386Sopenharmony_ciprivate:
889cb93a386Sopenharmony_ci    SkSL::Compiler& fCompiler;
890cb93a386Sopenharmony_ci    using INHERITED = SkSL::ExternalFunction;
891cb93a386Sopenharmony_ci};
892cb93a386Sopenharmony_ci
893cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterExternalFunction, r) {
894cb93a386Sopenharmony_ci    GrShaderCaps caps;
895cb93a386Sopenharmony_ci    SkSL::Compiler compiler(&caps);
896cb93a386Sopenharmony_ci    SkSL::Program::Settings settings;
897cb93a386Sopenharmony_ci    const char* src = "float main() { return externalSqrt(25); }";
898cb93a386Sopenharmony_ci    std::vector<std::unique_ptr<SkSL::ExternalFunction>> externalFunctions;
899cb93a386Sopenharmony_ci    externalFunctions.push_back(std::make_unique<ExternalSqrt>("externalSqrt", compiler));
900cb93a386Sopenharmony_ci    settings.fExternalFunctions = &externalFunctions;
901cb93a386Sopenharmony_ci    std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
902cb93a386Sopenharmony_ci            SkSL::ProgramKind::kGeneric, SkSL::String(src), settings);
903cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, program);
904cb93a386Sopenharmony_ci
905cb93a386Sopenharmony_ci    const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
906cb93a386Sopenharmony_ci
907cb93a386Sopenharmony_ci    skvm::Builder b;
908cb93a386Sopenharmony_ci    SkSL::ProgramToSkVM(*program, *main, &b, /*debugInfo=*/nullptr, /*uniforms=*/{});
909cb93a386Sopenharmony_ci    skvm::Program p = b.done();
910cb93a386Sopenharmony_ci
911cb93a386Sopenharmony_ci    float out;
912cb93a386Sopenharmony_ci    p.eval(1, &out);
913cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, out == 5.0);
914cb93a386Sopenharmony_ci}
915cb93a386Sopenharmony_ci
916cb93a386Sopenharmony_ciclass ExternalTable : public SkSL::ExternalFunction {
917cb93a386Sopenharmony_cipublic:
918cb93a386Sopenharmony_ci    ExternalTable(const char* name, SkSL::Compiler& compiler, skvm::Uniforms* uniforms)
919cb93a386Sopenharmony_ci            : INHERITED(name, *compiler.context().fTypes.fFloat)
920cb93a386Sopenharmony_ci            , fCompiler(compiler)
921cb93a386Sopenharmony_ci            , fTable{1, 2, 4, 8} {
922cb93a386Sopenharmony_ci        fAddr = uniforms->pushPtr(fTable);
923cb93a386Sopenharmony_ci    }
924cb93a386Sopenharmony_ci
925cb93a386Sopenharmony_ci    int callParameterCount() const override { return 1; }
926cb93a386Sopenharmony_ci
927cb93a386Sopenharmony_ci    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
928cb93a386Sopenharmony_ci        outTypes[0] = fCompiler.context().fTypes.fFloat.get();
929cb93a386Sopenharmony_ci    }
930cb93a386Sopenharmony_ci
931cb93a386Sopenharmony_ci    void call(skvm::Builder* b,
932cb93a386Sopenharmony_ci              skvm::F32* arguments,
933cb93a386Sopenharmony_ci              skvm::F32* outResult,
934cb93a386Sopenharmony_ci              skvm::I32 mask) const override {
935cb93a386Sopenharmony_ci        skvm::I32 index = skvm::trunc(arguments[0] * 4);
936cb93a386Sopenharmony_ci        index = max(0, min(index, 3));
937cb93a386Sopenharmony_ci        outResult[0] = b->gatherF(fAddr, index);
938cb93a386Sopenharmony_ci    }
939cb93a386Sopenharmony_ci
940cb93a386Sopenharmony_ciprivate:
941cb93a386Sopenharmony_ci    SkSL::Compiler& fCompiler;
942cb93a386Sopenharmony_ci    skvm::Uniform fAddr;
943cb93a386Sopenharmony_ci    float fTable[4];
944cb93a386Sopenharmony_ci    using INHERITED = SkSL::ExternalFunction;
945cb93a386Sopenharmony_ci};
946cb93a386Sopenharmony_ci
947cb93a386Sopenharmony_ciDEF_TEST(SkSLInterpreterExternalTable, r) {
948cb93a386Sopenharmony_ci    GrShaderCaps caps;
949cb93a386Sopenharmony_ci    SkSL::Compiler compiler(&caps);
950cb93a386Sopenharmony_ci    SkSL::Program::Settings settings;
951cb93a386Sopenharmony_ci    const char* src =
952cb93a386Sopenharmony_ci            "float4 main() { return float4(table(2), table(-1), table(0.4), table(0.6)); }";
953cb93a386Sopenharmony_ci    std::vector<std::unique_ptr<SkSL::ExternalFunction>> externalFunctions;
954cb93a386Sopenharmony_ci
955cb93a386Sopenharmony_ci    skvm::Builder b;
956cb93a386Sopenharmony_ci    skvm::Uniforms u(b.uniform(), 0);
957cb93a386Sopenharmony_ci
958cb93a386Sopenharmony_ci    externalFunctions.push_back(std::make_unique<ExternalTable>("table", compiler, &u));
959cb93a386Sopenharmony_ci    settings.fExternalFunctions = &externalFunctions;
960cb93a386Sopenharmony_ci    std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
961cb93a386Sopenharmony_ci            SkSL::ProgramKind::kGeneric, SkSL::String(src), settings);
962cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, program);
963cb93a386Sopenharmony_ci
964cb93a386Sopenharmony_ci    const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
965cb93a386Sopenharmony_ci
966cb93a386Sopenharmony_ci    SkSL::ProgramToSkVM(*program, *main, &b, /*debugInfo=*/nullptr, /*uniforms=*/{});
967cb93a386Sopenharmony_ci    skvm::Program p = b.done();
968cb93a386Sopenharmony_ci
969cb93a386Sopenharmony_ci    float out[4];
970cb93a386Sopenharmony_ci    p.eval(1, u.buf.data(), &out[0], &out[1], &out[2], &out[3]);
971cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, out[0] == 8.0);
972cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, out[1] == 1.0);
973cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, out[2] == 2.0);
974cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, out[3] == 4.0);
975cb93a386Sopenharmony_ci}
976