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