2019-03-21 15:05:37 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2019 Google LLC
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2020-02-20 20:42:29 +00:00
|
|
|
#include "include/core/SkM44.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/sksl/SkSLCompiler.h"
|
2021-04-13 14:41:57 +00:00
|
|
|
#include "src/sksl/codegen/SkSLVMCodeGenerator.h"
|
2021-04-13 13:42:05 +00:00
|
|
|
#include "src/sksl/ir/SkSLExternalFunction.h"
|
2021-12-10 17:03:35 +00:00
|
|
|
#include "src/sksl/tracing/SkVMDebugTrace.h"
|
2019-05-15 19:29:54 +00:00
|
|
|
#include "src/utils/SkJSON.h"
|
2019-03-21 15:05:37 +00:00
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "tests/Test.h"
|
2019-03-21 15:05:37 +00:00
|
|
|
|
2020-12-28 14:03:00 +00:00
|
|
|
struct ProgramBuilder {
|
|
|
|
ProgramBuilder(skiatest::Reporter* r, const char* src)
|
2021-10-20 19:44:59 +00:00
|
|
|
: fCompiler(&fCaps) {
|
2020-12-28 14:03:00 +00:00
|
|
|
SkSL::Program::Settings settings;
|
2021-01-07 19:38:08 +00:00
|
|
|
// The SkSL inliner is well tested in other contexts. Here, we disable inlining entirely,
|
|
|
|
// to stress-test the VM generator's handling of function calls with varying signatures.
|
|
|
|
settings.fInlineThreshold = 0;
|
2021-01-11 15:39:58 +00:00
|
|
|
// For convenience, so we can test functions other than (and not called by) main.
|
|
|
|
settings.fRemoveDeadFunctions = false;
|
2021-01-07 19:38:08 +00:00
|
|
|
|
2022-02-02 21:51:18 +00:00
|
|
|
fProgram = fCompiler.convertProgram(SkSL::ProgramKind::kGeneric, std::string(src),
|
2020-12-28 14:03:00 +00:00
|
|
|
settings);
|
|
|
|
if (!fProgram) {
|
|
|
|
ERRORF(r, "Program failed to compile:\n%s\n%s\n", src, fCompiler.errorText().c_str());
|
2020-04-02 15:38:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-19 14:19:02 +00:00
|
|
|
explicit operator bool() const { return fProgram != nullptr; }
|
2020-12-28 14:03:00 +00:00
|
|
|
SkSL::Program& operator*() { return *fProgram; }
|
|
|
|
|
2021-11-19 15:59:59 +00:00
|
|
|
SkSL::ShaderCaps fCaps;
|
2020-12-28 14:03:00 +00:00
|
|
|
SkSL::Compiler fCompiler;
|
|
|
|
std::unique_ptr<SkSL::Program> fProgram;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void verify_values(skiatest::Reporter* r,
|
|
|
|
const char* src,
|
|
|
|
const float* actual,
|
|
|
|
const float* expected,
|
|
|
|
int N,
|
2021-01-07 19:55:00 +00:00
|
|
|
bool exactCompare) {
|
|
|
|
auto exact_equiv = [](float x, float y) {
|
|
|
|
return x == y
|
|
|
|
|| (isnan(x) && isnan(y));
|
2020-12-28 14:03:00 +00:00
|
|
|
};
|
|
|
|
|
2021-01-07 19:55:00 +00:00
|
|
|
bool valid = true;
|
|
|
|
for (int i = 0; i < N; ++i) {
|
|
|
|
if (exactCompare && !exact_equiv(actual[i], expected[i])) {
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
if (!exactCompare && !SkScalarNearlyEqual(actual[i], expected[i])) {
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-28 14:03:00 +00:00
|
|
|
if (!valid) {
|
|
|
|
printf("for program: %s\n", src);
|
|
|
|
printf(" expected (");
|
|
|
|
const char* separator = "";
|
|
|
|
for (int i = 0; i < N; ++i) {
|
|
|
|
printf("%s%f", separator, expected[i]);
|
|
|
|
separator = ", ";
|
|
|
|
}
|
|
|
|
printf("), but received (");
|
|
|
|
separator = "";
|
|
|
|
for (int i = 0; i < N; ++i) {
|
|
|
|
printf("%s%f", separator, actual[i]);
|
|
|
|
separator = ", ";
|
|
|
|
}
|
|
|
|
printf(")\n");
|
2019-04-23 17:31:09 +00:00
|
|
|
}
|
2020-12-28 14:03:00 +00:00
|
|
|
REPORTER_ASSERT(r, valid);
|
2019-04-23 17:31:09 +00:00
|
|
|
}
|
|
|
|
|
2021-01-21 21:33:06 +00:00
|
|
|
void test(skiatest::Reporter* r, const char* src, float* in, const float* expected,
|
|
|
|
bool exactCompare = true) {
|
2020-12-28 14:03:00 +00:00
|
|
|
ProgramBuilder program(r, src);
|
|
|
|
if (!program) { return; }
|
|
|
|
|
|
|
|
const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
|
|
|
|
REPORTER_ASSERT(r, main);
|
|
|
|
|
|
|
|
skvm::Builder b;
|
|
|
|
SkSL::SkVMSignature sig;
|
2021-12-06 17:02:20 +00:00
|
|
|
SkSL::ProgramToSkVM(*program, *main, &b, /*debugTrace=*/nullptr, /*uniforms=*/{}, &sig);
|
2020-12-28 14:03:00 +00:00
|
|
|
skvm::Program p = b.done();
|
2019-06-13 15:23:57 +00:00
|
|
|
|
2021-01-11 18:16:28 +00:00
|
|
|
REPORTER_ASSERT(r, p.nargs() == (int)(sig.fParameterSlots + sig.fReturnSlots));
|
2020-12-28 14:03:00 +00:00
|
|
|
|
|
|
|
auto out = std::make_unique<float[]>(sig.fReturnSlots);
|
2021-01-11 18:16:28 +00:00
|
|
|
auto args = std::make_unique<void*[]>(sig.fParameterSlots + sig.fReturnSlots);
|
2020-12-28 14:03:00 +00:00
|
|
|
for (size_t i = 0; i < sig.fParameterSlots; ++i) {
|
2021-01-11 18:16:28 +00:00
|
|
|
args[i] = in + i;
|
2020-12-28 14:03:00 +00:00
|
|
|
}
|
|
|
|
for (size_t i = 0; i < sig.fReturnSlots; ++i) {
|
2021-01-11 18:16:28 +00:00
|
|
|
args[sig.fParameterSlots + i] = out.get() + i;
|
2019-06-14 14:17:16 +00:00
|
|
|
}
|
2019-06-13 15:23:57 +00:00
|
|
|
|
2020-12-28 14:03:00 +00:00
|
|
|
// TODO: Test with and without JIT?
|
|
|
|
p.eval(1, args.get());
|
|
|
|
|
2021-01-07 19:55:00 +00:00
|
|
|
verify_values(r, src, out.get(), expected, sig.fReturnSlots, exactCompare);
|
2020-12-28 14:03:00 +00:00
|
|
|
}
|
|
|
|
|
2021-01-21 21:33:06 +00:00
|
|
|
void test(skiatest::Reporter* r, const char* src,
|
|
|
|
float inR, float inG, float inB, float inA,
|
|
|
|
float exR, float exG, float exB, float exA) {
|
2020-12-28 14:03:00 +00:00
|
|
|
ProgramBuilder program(r, src);
|
|
|
|
if (!program) { return; }
|
|
|
|
|
|
|
|
const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
|
|
|
|
REPORTER_ASSERT(r, main);
|
|
|
|
|
|
|
|
skvm::Builder b;
|
2021-12-06 17:02:20 +00:00
|
|
|
SkSL::ProgramToSkVM(*program, *main, &b, /*debugTrace=*/nullptr, /*uniforms=*/{});
|
2020-12-28 14:03:00 +00:00
|
|
|
skvm::Program p = b.done();
|
|
|
|
|
|
|
|
// TODO: Test with and without JIT?
|
2021-01-11 18:16:28 +00:00
|
|
|
p.eval(1, &inR, &inG, &inB, &inA);
|
2020-12-28 14:03:00 +00:00
|
|
|
|
|
|
|
float actual[4] = { inR, inG, inB, inA };
|
|
|
|
float expected[4] = { exR, exG, exB, exA };
|
|
|
|
|
2021-01-07 19:55:00 +00:00
|
|
|
verify_values(r, src, actual, expected, 4, /*exactCompare=*/true);
|
2020-12-28 14:03:00 +00:00
|
|
|
|
|
|
|
// TODO: vec_test with skvm
|
|
|
|
}
|
|
|
|
|
2019-03-21 15:05:37 +00:00
|
|
|
DEF_TEST(SkSLInterpreterAdd, r) {
|
|
|
|
test(r, "void main(inout half4 color) { color.r = color.r + color.g; }", 0.25, 0.75, 0, 0, 1,
|
|
|
|
0.75, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { color += half4(1, 2, 3, 4); }", 4, 3, 2, 1, 5, 5, 5, 5);
|
|
|
|
test(r, "void main(inout half4 color) { half4 c = color; color += c; }", 0.25, 0.5, 0.75, 1,
|
|
|
|
0.5, 1, 1.5, 2);
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "void main(inout half4 color) { color.r = half(int(color.r) + int(color.g)); }", 1, 3, 0, 0,
|
2019-09-24 17:07:06 +00:00
|
|
|
4, 3, 0, 0);
|
2019-03-21 15:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterSubtract, r) {
|
|
|
|
test(r, "void main(inout half4 color) { color.r = color.r - color.g; }", 1, 0.75, 0, 0, 0.25,
|
|
|
|
0.75, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { color -= half4(1, 2, 3, 4); }", 5, 5, 5, 5, 4, 3, 2, 1);
|
|
|
|
test(r, "void main(inout half4 color) { half4 c = color; color -= c; }", 4, 3, 2, 1,
|
|
|
|
0, 0, 0, 0);
|
2019-05-07 20:13:02 +00:00
|
|
|
test(r, "void main(inout half4 color) { color.x = -color.x; }", 4, 3, 2, 1, -4, 3, 2, 1);
|
|
|
|
test(r, "void main(inout half4 color) { color = -color; }", 4, 3, 2, 1, -4, -3, -2, -1);
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "void main(inout half4 color) { color.r = half(int(color.r) - int(color.g)); }", 3, 1, 0, 0,
|
2019-09-24 17:07:06 +00:00
|
|
|
2, 1, 0, 0);
|
2019-03-21 15:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterMultiply, r) {
|
|
|
|
test(r, "void main(inout half4 color) { color.r = color.r * color.g; }", 2, 3, 0, 0, 6, 3, 0,
|
|
|
|
0);
|
|
|
|
test(r, "void main(inout half4 color) { color *= half4(1, 2, 3, 4); }", 2, 3, 4, 5, 2, 6, 12,
|
|
|
|
20);
|
|
|
|
test(r, "void main(inout half4 color) { half4 c = color; color *= c; }", 4, 3, 2, 1,
|
|
|
|
16, 9, 4, 1);
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "void main(inout half4 color) { color.r = half(int(color.r) * int(color.g)); }", 3, -2, 0, 0,
|
2019-09-24 17:07:06 +00:00
|
|
|
-6, -2, 0, 0);
|
2019-03-21 15:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterDivide, r) {
|
|
|
|
test(r, "void main(inout half4 color) { color.r = color.r / color.g; }", 1, 2, 0, 0, 0.5, 2, 0,
|
|
|
|
0);
|
|
|
|
test(r, "void main(inout half4 color) { color /= half4(1, 2, 3, 4); }", 12, 12, 12, 12, 12, 6,
|
|
|
|
4, 3);
|
|
|
|
test(r, "void main(inout half4 color) { half4 c = color; color /= c; }", 4, 3, 2, 1,
|
|
|
|
1, 1, 1, 1);
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "void main(inout half4 color) { color.r = half(int(color.r) / int(color.g)); }", 8, -2, 0, 0,
|
2019-09-24 17:07:06 +00:00
|
|
|
-4, -2, 0, 0);
|
2019-03-21 15:05:37 +00:00
|
|
|
}
|
|
|
|
|
2019-09-23 15:43:45 +00:00
|
|
|
DEF_TEST(SkSLInterpreterAnd, r) {
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r > color.g && color.g > color.b) "
|
|
|
|
"color = half4(color.a); }", 2, 1, 0, 3, 3, 3, 3, 3);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r > color.g && color.g > color.b) "
|
|
|
|
"color = half4(color.a); }", 1, 1, 0, 3, 1, 1, 0, 3);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r > color.g && color.g > color.b) "
|
|
|
|
"color = half4(color.a); }", 2, 1, 1, 3, 2, 1, 1, 3);
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "half global; bool update() { global = 123; return true; }"
|
2019-09-23 15:43:45 +00:00
|
|
|
"void main(inout half4 color) { global = 0; if (color.r > color.g && update()) "
|
2021-01-07 19:38:08 +00:00
|
|
|
"color = half4(color.a); color.a = global; }", 2, 1, 1, 3, 3, 3, 3, 123);
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "half global; bool update() { global = 123; return true; }"
|
2019-09-23 15:43:45 +00:00
|
|
|
"void main(inout half4 color) { global = 0; if (color.r > color.g && update()) "
|
2021-01-07 19:38:08 +00:00
|
|
|
"color = half4(color.a); color.a = global; }", 1, 1, 1, 3, 1, 1, 1, 0);
|
2019-09-23 15:43:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterOr, r) {
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r > color.g || color.g > color.b) "
|
|
|
|
"color = half4(color.a); }", 2, 1, 0, 3, 3, 3, 3, 3);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r > color.g || color.g > color.b) "
|
|
|
|
"color = half4(color.a); }", 1, 1, 0, 3, 3, 3, 3, 3);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r > color.g || color.g > color.b) "
|
|
|
|
"color = half4(color.a); }", 1, 1, 1, 3, 1, 1, 1, 3);
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "half global; bool update() { global = 123; return true; }"
|
2019-09-23 15:43:45 +00:00
|
|
|
"void main(inout half4 color) { global = 0; if (color.r > color.g || update()) "
|
2021-01-07 19:38:08 +00:00
|
|
|
"color = half4(color.a); color.a = global; }", 1, 1, 1, 3, 3, 3, 3, 123);
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "half global; bool update() { global = 123; return true; }"
|
2019-09-23 15:43:45 +00:00
|
|
|
"void main(inout half4 color) { global = 0; if (color.r > color.g || update()) "
|
2021-01-07 19:38:08 +00:00
|
|
|
"color = half4(color.a); color.a = global; }", 2, 1, 1, 3, 3, 3, 3, 0);
|
2019-09-23 15:43:45 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 21:16:03 +00:00
|
|
|
DEF_TEST(SkSLInterpreterMatrix, r) {
|
2019-06-14 14:17:16 +00:00
|
|
|
float in[16];
|
|
|
|
float expected[16];
|
2019-05-28 21:16:03 +00:00
|
|
|
|
|
|
|
// Constructing matrix from scalar produces a diagonal matrix
|
2020-12-22 18:35:55 +00:00
|
|
|
in[0] = 2.0f;
|
|
|
|
expected[0] = 4.0f;
|
2019-05-28 21:16:03 +00:00
|
|
|
test(r, "float main(float x) { float4x4 m = float4x4(x); return m[1][1] + m[1][2] + m[2][2]; }",
|
2019-09-27 14:25:57 +00:00
|
|
|
in, expected);
|
2019-05-28 21:16:03 +00:00
|
|
|
|
|
|
|
// Constructing from a different-sized matrix fills the remaining space with the identity matrix
|
2020-12-22 18:35:55 +00:00
|
|
|
expected[0] = 3.0f;
|
2019-05-28 21:16:03 +00:00
|
|
|
test(r, "float main(float x) {"
|
2020-12-22 18:35:55 +00:00
|
|
|
"float2x2 m = float2x2(x);"
|
2019-05-28 21:16:03 +00:00
|
|
|
"float4x4 m2 = float4x4(m);"
|
|
|
|
"return m2[0][0] + m2[3][3]; }",
|
2019-09-27 14:25:57 +00:00
|
|
|
in, expected);
|
2019-05-28 21:16:03 +00:00
|
|
|
|
|
|
|
// Constructing a matrix from vectors or scalars fills in values in column-major order
|
|
|
|
in[0] = 1.0f;
|
|
|
|
in[1] = 2.0f;
|
|
|
|
in[2] = 4.0f;
|
|
|
|
in[3] = 8.0f;
|
|
|
|
expected[0] = 6.0f;
|
|
|
|
test(r, "float main(float4 v) { float2x2 m = float2x2(v); return m[0][1] + m[1][0]; }",
|
2019-09-27 14:25:57 +00:00
|
|
|
in, expected);
|
2019-05-28 21:16:03 +00:00
|
|
|
|
|
|
|
expected[0] = 10.0f;
|
|
|
|
test(r, "float main(float4 v) {"
|
|
|
|
"float2x2 m = float2x2(v.x, v.y, v.w, v.z);"
|
|
|
|
"return m[0][1] + m[1][0]; }",
|
2019-09-27 14:25:57 +00:00
|
|
|
in, expected);
|
2019-05-28 21:16:03 +00:00
|
|
|
|
2019-05-29 19:21:52 +00:00
|
|
|
// Initialize 16 values to be used as inputs to matrix tests
|
|
|
|
for (int i = 0; i < 16; ++i) { in[i] = (float)i; }
|
|
|
|
|
|
|
|
// M+M, M-S, S-M
|
|
|
|
for (int i = 0; i < 16; ++i) { expected[i] = (float)(2 * i); }
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float4x4 main(float4x4 m) { return m + m; }", in, expected);
|
2019-05-29 19:21:52 +00:00
|
|
|
for (int i = 0; i < 16; ++i) { expected[i] = (float)(i + 3); }
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float4x4 main(float4x4 m) { return m + 3.0; }", in, expected);
|
|
|
|
test(r, "float4x4 main(float4x4 m) { return 3.0 + m; }", in, expected);
|
2019-05-29 19:21:52 +00:00
|
|
|
|
|
|
|
// M-M, M-S, S-M
|
2020-12-22 18:35:55 +00:00
|
|
|
for (int i = 0; i < 4; ++i) { expected[i] = 4.0f; }
|
|
|
|
test(r, "float2x2 main(float2x2 m1, float2x2 m2) { return m2 - m1; }", in, expected);
|
2019-05-29 19:21:52 +00:00
|
|
|
for (int i = 0; i < 16; ++i) { expected[i] = (float)(i - 3); }
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float4x4 main(float4x4 m) { return m - 3.0; }", in, expected);
|
2019-05-29 19:21:52 +00:00
|
|
|
for (int i = 0; i < 16; ++i) { expected[i] = (float)(3 - i); }
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float4x4 main(float4x4 m) { return 3.0 - m; }", in, expected);
|
2019-05-29 19:21:52 +00:00
|
|
|
|
|
|
|
// M*S, S*M, M/S, S/M
|
|
|
|
for (int i = 0; i < 16; ++i) { expected[i] = (float)(i * 3); }
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float4x4 main(float4x4 m) { return m * 3.0; }", in, expected);
|
|
|
|
test(r, "float4x4 main(float4x4 m) { return 3.0 * m; }", in, expected);
|
2019-05-29 19:21:52 +00:00
|
|
|
for (int i = 0; i < 16; ++i) { expected[i] = (float)(i) / 2.0f; }
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float4x4 main(float4x4 m) { return m / 2.0; }", in, expected);
|
2019-05-29 21:04:54 +00:00
|
|
|
for (int i = 0; i < 16; ++i) { expected[i] = 1.0f / (float)(i + 1); }
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float4x4 main(float4x4 m) { return 1.0 / (m + 1); }", in, expected);
|
2019-05-29 19:21:52 +00:00
|
|
|
|
2021-01-15 20:30:47 +00:00
|
|
|
// Matrix negation
|
2019-05-29 19:21:52 +00:00
|
|
|
for (int i = 0; i < 16; ++i) { expected[i] = (float)(-i); }
|
2021-01-15 20:30:47 +00:00
|
|
|
test(r, "float4x4 main(float4x4 m) { return -m; }", in, expected);
|
2019-05-28 21:16:03 +00:00
|
|
|
|
2019-05-29 19:34:36 +00:00
|
|
|
// M*V, V*M
|
2020-12-22 18:35:55 +00:00
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
expected[i] = 9.0f*i + 10.0f*(i+3) + 11.0f*(i+6);
|
2019-05-29 19:34:36 +00:00
|
|
|
}
|
2020-12-22 18:35:55 +00:00
|
|
|
test(r, "float3 main(float3x3 m, float3 v) { return m * v; }", in, expected);
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
expected[i] = 9.0f*(3*i) + 10.0f*(3*i+1) + 11.0f*(3*i+2);
|
2019-05-29 19:34:36 +00:00
|
|
|
}
|
2020-12-22 18:35:55 +00:00
|
|
|
test(r, "float3 main(float3x3 m, float3 v) { return v * m; }", in, expected);
|
2019-05-29 19:34:36 +00:00
|
|
|
|
|
|
|
// M*M
|
|
|
|
{
|
2020-04-06 14:41:09 +00:00
|
|
|
SkM44 m = SkM44::ColMajor(in);
|
2020-01-22 19:31:21 +00:00
|
|
|
SkM44 m2;
|
|
|
|
float in2[16];
|
2019-05-29 19:34:36 +00:00
|
|
|
for (int i = 0; i < 16; ++i) {
|
2020-01-22 19:31:21 +00:00
|
|
|
in2[i] = (i + 4) % 16;
|
2019-05-29 19:34:36 +00:00
|
|
|
}
|
2020-04-06 14:41:09 +00:00
|
|
|
m2 = SkM44::ColMajor(in2);
|
2019-05-29 19:34:36 +00:00
|
|
|
m.setConcat(m, m2);
|
|
|
|
// Rearrange the columns on the RHS so we detect left-hand/right-hand errors
|
|
|
|
test(r, "float4x4 main(float4x4 m) { return m * float4x4(m[1], m[2], m[3], m[0]); }",
|
2019-09-27 14:25:57 +00:00
|
|
|
in, (float*)&m);
|
2019-05-29 19:34:36 +00:00
|
|
|
}
|
2019-05-28 21:16:03 +00:00
|
|
|
}
|
|
|
|
|
2019-05-16 19:38:00 +00:00
|
|
|
DEF_TEST(SkSLInterpreterTernary, r) {
|
|
|
|
test(r, "void main(inout half4 color) { color.r = color.g > color.b ? color.g : color.b; }",
|
|
|
|
0, 1, 2, 0, 2, 1, 2, 0);
|
|
|
|
test(r, "void main(inout half4 color) { color.r = color.g > color.b ? color.g : color.b; }",
|
|
|
|
0, 3, 2, 0, 3, 3, 2, 0);
|
|
|
|
}
|
|
|
|
|
2019-05-14 17:37:30 +00:00
|
|
|
DEF_TEST(SkSLInterpreterCast, r) {
|
2019-06-14 14:17:16 +00:00
|
|
|
union Val {
|
|
|
|
float f;
|
|
|
|
int32_t s;
|
|
|
|
};
|
|
|
|
|
|
|
|
Val input[2];
|
|
|
|
Val expected[2];
|
|
|
|
|
|
|
|
input[0].s = 3;
|
|
|
|
input[1].s = -5;
|
|
|
|
expected[0].f = 3.0f;
|
|
|
|
expected[1].f = -5.0f;
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float main(int x) { return float (x); }", (float*)input, (float*)expected);
|
|
|
|
test(r, "float2 main(int2 x) { return float2(x); }", (float*)input, (float*)expected);
|
2019-06-14 14:17:16 +00:00
|
|
|
|
|
|
|
input[0].f = 3.0f;
|
|
|
|
input[1].f = -5.0f;
|
|
|
|
expected[0].s = 3;
|
|
|
|
expected[1].s = -5;
|
2020-04-02 15:38:40 +00:00
|
|
|
test(r, "int main(float x) { return int (x); }", (float*)input, (float*)expected);
|
|
|
|
test(r, "int2 main(float2 x) { return int2(x); }", (float*)input, (float*)expected);
|
2019-06-14 14:17:16 +00:00
|
|
|
|
|
|
|
input[0].s = 3;
|
|
|
|
expected[0].f = 3.0f;
|
|
|
|
expected[1].f = 3.0f;
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float2 main(int x) { return float2(x); }", (float*)input, (float*)expected);
|
2019-05-14 17:37:30 +00:00
|
|
|
}
|
|
|
|
|
2019-03-21 15:05:37 +00:00
|
|
|
DEF_TEST(SkSLInterpreterIf, r) {
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r > color.g) color.a = 1; }", 5, 3, 0, 0,
|
|
|
|
5, 3, 0, 1);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r > color.g) color.a = 1; }", 5, 5, 0, 0,
|
|
|
|
5, 5, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r > color.g) color.a = 1; }", 5, 6, 0, 0,
|
|
|
|
5, 6, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r < color.g) color.a = 1; }", 3, 5, 0, 0,
|
|
|
|
3, 5, 0, 1);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r < color.g) color.a = 1; }", 5, 5, 0, 0,
|
|
|
|
5, 5, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r < color.g) color.a = 1; }", 6, 5, 0, 0,
|
|
|
|
6, 5, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r >= color.g) color.a = 1; }", 5, 3, 0, 0,
|
|
|
|
5, 3, 0, 1);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r >= color.g) color.a = 1; }", 5, 5, 0, 0,
|
|
|
|
5, 5, 0, 1);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r >= color.g) color.a = 1; }", 5, 6, 0, 0,
|
|
|
|
5, 6, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r <= color.g) color.a = 1; }", 3, 5, 0, 0,
|
|
|
|
3, 5, 0, 1);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r <= color.g) color.a = 1; }", 5, 5, 0, 0,
|
|
|
|
5, 5, 0, 1);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r <= color.g) color.a = 1; }", 6, 5, 0, 0,
|
|
|
|
6, 5, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r == color.g) color.a = 1; }", 2, 2, 0, 0,
|
|
|
|
2, 2, 0, 1);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r == color.g) color.a = 1; }", 2, -2, 0, 0,
|
|
|
|
2, -2, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r != color.g) color.a = 1; }", 2, 2, 0, 0,
|
|
|
|
2, 2, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r != color.g) color.a = 1; }", 2, -2, 0, 0,
|
|
|
|
2, -2, 0, 1);
|
2019-09-23 16:38:40 +00:00
|
|
|
test(r, "void main(inout half4 color) { if (!(color.r == color.g)) color.a = 1; }", 2, 2, 0, 0,
|
|
|
|
2, 2, 0, 0);
|
|
|
|
test(r, "void main(inout half4 color) { if (!(color.r == color.g)) color.a = 1; }", 2, -2, 0, 0,
|
|
|
|
2, -2, 0, 1);
|
2019-03-21 15:05:37 +00:00
|
|
|
test(r, "void main(inout half4 color) { if (color.r == color.g) color.a = 1; else "
|
|
|
|
"color.a = 2; }", 1, 1, 0, 0, 1, 1, 0, 1);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.r == color.g) color.a = 1; else "
|
|
|
|
"color.a = 2; }", 2, -2, 0, 0, 2, -2, 0, 2);
|
|
|
|
}
|
|
|
|
|
2019-05-29 15:19:00 +00:00
|
|
|
DEF_TEST(SkSLInterpreterIfVector, r) {
|
|
|
|
test(r, "void main(inout half4 color) { if (color.rg == color.ba) color.a = 1; }",
|
|
|
|
1, 2, 1, 2, 1, 2, 1, 1);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.rg == color.ba) color.a = 1; }",
|
|
|
|
1, 2, 3, 2, 1, 2, 3, 2);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.rg != color.ba) color.a = 1; }",
|
|
|
|
1, 2, 1, 2, 1, 2, 1, 2);
|
|
|
|
test(r, "void main(inout half4 color) { if (color.rg != color.ba) color.a = 1; }",
|
|
|
|
1, 2, 3, 2, 1, 2, 3, 1);
|
|
|
|
}
|
|
|
|
|
2019-03-21 15:05:37 +00:00
|
|
|
DEF_TEST(SkSLInterpreterFor, r) {
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "void main(inout half4 color) { for (int i = 1; i <= 10; ++i) color.r += half(i); }",
|
2020-12-28 14:03:00 +00:00
|
|
|
0, 0, 0, 0,
|
2021-01-13 20:06:17 +00:00
|
|
|
55, 0, 0, 0);
|
2019-03-21 15:05:37 +00:00
|
|
|
test(r,
|
|
|
|
"void main(inout half4 color) {"
|
|
|
|
" for (int i = 1; i <= 10; ++i)"
|
2021-01-12 22:15:30 +00:00
|
|
|
" for (int j = 1; j <= 10; ++j)"
|
2021-01-13 22:48:36 +00:00
|
|
|
" if (j >= i) { color.r += half(j); }"
|
2019-03-21 15:05:37 +00:00
|
|
|
"}",
|
|
|
|
0, 0, 0, 0,
|
2021-01-13 20:06:17 +00:00
|
|
|
385, 0, 0, 0);
|
2019-03-21 15:05:37 +00:00
|
|
|
test(r,
|
|
|
|
"void main(inout half4 color) {"
|
|
|
|
" for (int i = 1; i <= 10; ++i)"
|
2021-01-12 22:15:30 +00:00
|
|
|
" for (int j = 1; j < 20 ; ++j) {"
|
2019-03-21 15:05:37 +00:00
|
|
|
" if (i == j) continue;"
|
|
|
|
" if (j > 10) break;"
|
2021-01-13 22:48:36 +00:00
|
|
|
" color.r += half(j);"
|
2019-03-21 15:05:37 +00:00
|
|
|
" }"
|
|
|
|
"}",
|
|
|
|
0, 0, 0, 0,
|
2021-01-13 20:06:17 +00:00
|
|
|
495, 0, 0, 0);
|
2019-03-21 15:05:37 +00:00
|
|
|
}
|
|
|
|
|
2019-05-17 18:26:53 +00:00
|
|
|
DEF_TEST(SkSLInterpreterPrefixPostfix, r) {
|
|
|
|
test(r, "void main(inout half4 color) { color.r = ++color.g; }", 1, 2, 3, 4, 3, 3, 3, 4);
|
|
|
|
test(r, "void main(inout half4 color) { color.r = color.g++; }", 1, 2, 3, 4, 2, 3, 3, 4);
|
|
|
|
}
|
|
|
|
|
2019-03-21 15:05:37 +00:00
|
|
|
DEF_TEST(SkSLInterpreterSwizzle, r) {
|
|
|
|
test(r, "void main(inout half4 color) { color = color.abgr; }", 1, 2, 3, 4, 4, 3, 2, 1);
|
|
|
|
test(r, "void main(inout half4 color) { color.rgb = half4(5, 6, 7, 8).bbg; }", 1, 2, 3, 4, 7, 7,
|
|
|
|
6, 4);
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "void main(inout half4 color) { color.bgr = half3(5, 6, 7); }", 1, 2, 3, 4, 7, 6,
|
2019-03-21 15:05:37 +00:00
|
|
|
5, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterGlobal, r) {
|
2021-01-13 22:48:36 +00:00
|
|
|
test(r, "int x; void main(inout half4 color) { x = 10; color.b = half(x); }", 1, 2, 3, 4, 1, 2,
|
|
|
|
10, 4);
|
2019-05-15 17:02:13 +00:00
|
|
|
test(r, "float4 x; void main(inout float4 color) { x = color * 2; color = x; }",
|
|
|
|
1, 2, 3, 4, 2, 4, 6, 8);
|
|
|
|
test(r, "float4 x; void main(inout float4 color) { x = float4(5, 6, 7, 8); color = x.wzyx; }",
|
|
|
|
1, 2, 3, 4, 8, 7, 6, 5);
|
2019-05-16 13:42:16 +00:00
|
|
|
test(r, "float4 x; void main(inout float4 color) { x.wzyx = float4(5, 6, 7, 8); color = x; }",
|
|
|
|
1, 2, 3, 4, 8, 7, 6, 5);
|
2019-03-21 15:05:37 +00:00
|
|
|
}
|
2019-04-23 17:31:09 +00:00
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterGeneric, r) {
|
|
|
|
float value1 = 5;
|
|
|
|
float expected1 = 25;
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float main(float x) { return x * x; }", &value1, &expected1);
|
2019-04-23 17:31:09 +00:00
|
|
|
float value2[2] = { 5, 25 };
|
|
|
|
float expected2[2] = { 25, 625 };
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float2 main(float x, float y) { return float2(x * x, y * y); }", value2, expected2);
|
2019-04-23 17:31:09 +00:00
|
|
|
}
|
2019-05-09 17:13:25 +00:00
|
|
|
|
2021-01-26 19:05:31 +00:00
|
|
|
DEF_TEST(SkSLInterpreterFieldAccessComplex, r) {
|
|
|
|
const char* src = R"(
|
|
|
|
struct P { float x; float y; };
|
|
|
|
P make_point() { P p; p.x = 7; p.y = 3; return p; }
|
|
|
|
float main() { return make_point().y; }
|
|
|
|
)";
|
|
|
|
|
|
|
|
float expected = 3.0f;
|
|
|
|
test(r, src, /*in=*/nullptr, &expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterIndexComplex, r) {
|
|
|
|
const char* src = R"(
|
|
|
|
float2x2 make_mtx() { return float2x2(1, 2, 3, 4); }
|
|
|
|
float main() { return make_mtx()[1][0]; }
|
|
|
|
)";
|
|
|
|
|
|
|
|
float expected = 3.0f;
|
|
|
|
test(r, src, /*in=*/nullptr, &expected);
|
|
|
|
}
|
|
|
|
|
2019-05-23 19:51:06 +00:00
|
|
|
DEF_TEST(SkSLInterpreterCompound, r) {
|
|
|
|
struct RectAndColor { SkIRect fRect; SkColor4f fColor; };
|
|
|
|
struct ManyRects { int fNumRects; RectAndColor fRects[4]; };
|
|
|
|
|
|
|
|
const char* src =
|
|
|
|
// Some struct definitions
|
|
|
|
"struct Point { int x; int y; };\n"
|
|
|
|
"struct Rect { Point p0; Point p1; };\n"
|
|
|
|
"struct RectAndColor { Rect r; float4 color; };\n"
|
|
|
|
|
|
|
|
// Structs as globals, parameters, return values
|
|
|
|
"RectAndColor temp;\n"
|
|
|
|
"int rect_height(Rect r) { return r.p1.y - r.p0.y; }\n"
|
|
|
|
"RectAndColor make_blue_rect(int w, int h) {\n"
|
|
|
|
" temp.r.p0.x = temp.r.p0.y = 0;\n"
|
|
|
|
" temp.r.p1.x = w; temp.r.p1.y = h;\n"
|
|
|
|
" temp.color = float4(0, 1, 0, 1);\n"
|
|
|
|
" return temp;\n"
|
|
|
|
"}\n"
|
|
|
|
|
|
|
|
// Initialization and assignment of types larger than 4 slots
|
|
|
|
"RectAndColor init_big(RectAndColor r) { RectAndColor s = r; return s; }\n"
|
|
|
|
"RectAndColor copy_big(RectAndColor r) { RectAndColor s; s = r; return s; }\n"
|
|
|
|
|
|
|
|
// Same for arrays, including some non-constant indexing
|
|
|
|
"int median(int a[15]) { return a[7]; }\n"
|
2020-12-03 15:37:45 +00:00
|
|
|
|
|
|
|
"float tempFloats[8];\n"
|
|
|
|
"float sums(float a[8]) {\n"
|
2019-05-23 19:51:06 +00:00
|
|
|
" tempFloats[0] = a[0];\n"
|
|
|
|
" for (int i = 1; i < 8; ++i) { tempFloats[i] = tempFloats[i - 1] + a[i]; }\n"
|
2020-12-03 15:37:45 +00:00
|
|
|
" return tempFloats[7];\n"
|
2019-05-23 19:51:06 +00:00
|
|
|
"}\n"
|
|
|
|
|
2021-01-11 18:16:28 +00:00
|
|
|
// Uniforms, array-of-structs
|
2019-09-26 17:04:48 +00:00
|
|
|
"uniform Rect gRects[4];\n"
|
2021-01-11 18:16:28 +00:00
|
|
|
"Rect get_rect_2() { return gRects[2]; }\n"
|
2019-05-23 19:51:06 +00:00
|
|
|
|
|
|
|
// Kitchen sink (swizzles, inout, SoAoS)
|
|
|
|
"struct ManyRects { int numRects; RectAndColor rects[4]; };\n"
|
|
|
|
"void fill_rects(inout ManyRects mr) {\n"
|
2021-01-12 22:15:30 +00:00
|
|
|
" for (int i = 0; i < 4; ++i) {\n"
|
|
|
|
" if (i >= mr.numRects) { break; }\n"
|
2019-05-23 19:51:06 +00:00
|
|
|
" mr.rects[i].r = gRects[i];\n"
|
2021-01-13 22:48:36 +00:00
|
|
|
" float b = float(mr.rects[i].r.p1.y);\n"
|
2019-05-23 19:51:06 +00:00
|
|
|
" mr.rects[i].color = float4(b, b, b, b);\n"
|
|
|
|
" }\n"
|
|
|
|
"}\n";
|
|
|
|
|
2021-01-11 18:16:28 +00:00
|
|
|
ProgramBuilder program(r, src);
|
2019-05-23 19:51:06 +00:00
|
|
|
|
2021-01-11 18:16:28 +00:00
|
|
|
auto rect_height = SkSL::Program_GetFunction(*program, "rect_height"),
|
|
|
|
make_blue_rect = SkSL::Program_GetFunction(*program, "make_blue_rect"),
|
|
|
|
median = SkSL::Program_GetFunction(*program, "median"),
|
|
|
|
sums = SkSL::Program_GetFunction(*program, "sums"),
|
|
|
|
get_rect_2 = SkSL::Program_GetFunction(*program, "get_rect_2"),
|
|
|
|
fill_rects = SkSL::Program_GetFunction(*program, "fill_rects");
|
2019-05-23 19:51:06 +00:00
|
|
|
|
|
|
|
SkIRect gRects[4] = { { 1,2,3,4 }, { 5,6,7,8 }, { 9,10,11,12 }, { 13,14,15,16 } };
|
2021-01-11 18:16:28 +00:00
|
|
|
|
|
|
|
auto build = [&](const SkSL::FunctionDefinition* fn) {
|
|
|
|
skvm::Builder b;
|
2021-08-03 20:43:14 +00:00
|
|
|
skvm::UPtr uniformPtr = b.uniform();
|
2021-01-11 18:16:28 +00:00
|
|
|
skvm::Val uniforms[16];
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
uniforms[i] = b.uniform32(uniformPtr, i * sizeof(int)).id;
|
|
|
|
}
|
2021-12-06 17:02:20 +00:00
|
|
|
SkSL::ProgramToSkVM(*program, *fn, &b, /*debugTrace=*/nullptr, SkMakeSpan(uniforms));
|
2021-01-11 18:16:28 +00:00
|
|
|
return b.done();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Args {
|
|
|
|
Args(void* uniformData) { fArgs.push_back(uniformData); }
|
|
|
|
void add(void* base, int n) {
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
fArgs.push_back(SkTAddOffset<void>(base, i * sizeof(float)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::vector<void*> fArgs;
|
|
|
|
};
|
2019-05-23 19:51:06 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
SkIRect in = SkIRect::MakeXYWH(10, 10, 20, 30);
|
2020-04-02 15:38:40 +00:00
|
|
|
int out = 0;
|
2021-01-11 18:16:28 +00:00
|
|
|
skvm::Program p = build(rect_height);
|
|
|
|
Args args(gRects);
|
|
|
|
args.add(&in, 4);
|
|
|
|
args.add(&out, 1);
|
|
|
|
p.eval(1, args.fArgs.data());
|
2020-04-02 15:38:40 +00:00
|
|
|
REPORTER_ASSERT(r, out == 30);
|
2019-05-23 19:51:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
int in[2] = { 15, 25 };
|
2020-04-02 15:38:40 +00:00
|
|
|
RectAndColor out;
|
2021-01-11 18:16:28 +00:00
|
|
|
skvm::Program p = build(make_blue_rect);
|
|
|
|
Args args(gRects);
|
|
|
|
args.add(&in, 2);
|
|
|
|
args.add(&out, 8);
|
|
|
|
p.eval(1, args.fArgs.data());
|
2020-04-02 15:38:40 +00:00
|
|
|
REPORTER_ASSERT(r, out.fRect.width() == 15);
|
|
|
|
REPORTER_ASSERT(r, out.fRect.height() == 25);
|
2019-05-23 19:51:06 +00:00
|
|
|
SkColor4f blue = { 0.0f, 1.0f, 0.0f, 1.0f };
|
2020-04-02 15:38:40 +00:00
|
|
|
REPORTER_ASSERT(r, out.fColor == blue);
|
2019-05-23 19:51:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
int in[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
2020-04-02 15:38:40 +00:00
|
|
|
int out = 0;
|
2021-01-11 18:16:28 +00:00
|
|
|
skvm::Program p = build(median);
|
|
|
|
Args args(gRects);
|
|
|
|
args.add(&in, 15);
|
|
|
|
args.add(&out, 1);
|
|
|
|
p.eval(1, args.fArgs.data());
|
2020-04-02 15:38:40 +00:00
|
|
|
REPORTER_ASSERT(r, out == 8);
|
2019-05-23 19:51:06 +00:00
|
|
|
}
|
|
|
|
|
2021-01-19 21:33:11 +00:00
|
|
|
{
|
2019-05-23 19:51:06 +00:00
|
|
|
float in[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
2020-12-03 15:37:45 +00:00
|
|
|
float out = 0;
|
2021-01-11 18:16:28 +00:00
|
|
|
skvm::Program p = build(sums);
|
|
|
|
Args args(gRects);
|
|
|
|
args.add(&in, 8);
|
|
|
|
args.add(&out, 1);
|
|
|
|
p.eval(1, args.fArgs.data());
|
2020-12-03 15:37:45 +00:00
|
|
|
REPORTER_ASSERT(r, out == static_cast<float>((7 + 1) * (7 + 2) / 2));
|
2019-05-23 19:51:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2020-04-02 15:38:40 +00:00
|
|
|
SkIRect out = SkIRect::MakeEmpty();
|
2021-01-11 18:16:28 +00:00
|
|
|
skvm::Program p = build(get_rect_2);
|
|
|
|
Args args(gRects);
|
|
|
|
args.add(&out, 4);
|
|
|
|
p.eval(1, args.fArgs.data());
|
2020-04-02 15:38:40 +00:00
|
|
|
REPORTER_ASSERT(r, out == gRects[2]);
|
2019-05-23 19:51:06 +00:00
|
|
|
}
|
|
|
|
|
2021-01-19 21:33:11 +00:00
|
|
|
{
|
2019-05-23 19:51:06 +00:00
|
|
|
ManyRects in;
|
|
|
|
memset(&in, 0, sizeof(in));
|
|
|
|
in.fNumRects = 2;
|
2021-01-11 18:16:28 +00:00
|
|
|
skvm::Program p = build(fill_rects);
|
|
|
|
Args args(gRects);
|
|
|
|
args.add(&in, 33);
|
|
|
|
p.eval(1, args.fArgs.data());
|
2019-05-23 19:51:06 +00:00
|
|
|
ManyRects expected;
|
|
|
|
memset(&expected, 0, sizeof(expected));
|
|
|
|
expected.fNumRects = 2;
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
expected.fRects[i].fRect = gRects[i];
|
|
|
|
float c = gRects[i].fBottom;
|
|
|
|
expected.fRects[i].fColor = { c, c, c, c };
|
|
|
|
}
|
|
|
|
REPORTER_ASSERT(r, memcmp(&in, &expected, sizeof(in)) == 0);
|
|
|
|
}
|
|
|
|
}
|
2019-05-15 19:29:54 +00:00
|
|
|
|
2019-07-18 21:00:34 +00:00
|
|
|
static void expect_failure(skiatest::Reporter* r, const char* src) {
|
2021-11-19 15:59:59 +00:00
|
|
|
SkSL::ShaderCaps caps;
|
2020-11-18 20:38:39 +00:00
|
|
|
SkSL::Compiler compiler(&caps);
|
2020-09-11 16:10:43 +00:00
|
|
|
SkSL::Program::Settings settings;
|
2021-02-16 18:29:15 +00:00
|
|
|
auto program = compiler.convertProgram(SkSL::ProgramKind::kGeneric,
|
2022-02-02 21:51:18 +00:00
|
|
|
std::string(src), settings);
|
2021-01-11 18:15:23 +00:00
|
|
|
REPORTER_ASSERT(r, !program);
|
2019-07-18 21:00:34 +00:00
|
|
|
}
|
|
|
|
|
2020-12-30 20:06:22 +00:00
|
|
|
DEF_TEST(SkSLInterpreterRestrictLoops, r) {
|
|
|
|
// while and do-while loops are not allowed
|
|
|
|
expect_failure(r, "void main(inout float x) { while (x < 1) { x++; } }");
|
|
|
|
expect_failure(r, "void main(inout float x) { do { x++; } while (x < 1); }");
|
|
|
|
}
|
|
|
|
|
2021-01-07 19:38:08 +00:00
|
|
|
DEF_TEST(SkSLInterpreterReturnThenCall, r) {
|
|
|
|
// Test that early returns disable execution in subsequently called functions
|
|
|
|
const char* src = R"(
|
|
|
|
float y;
|
|
|
|
void inc () { ++y; }
|
|
|
|
void maybe_inc() { if (y < 0) return; inc(); }
|
|
|
|
void main(inout float x) { y = x; maybe_inc(); x = y; }
|
|
|
|
)";
|
|
|
|
|
|
|
|
ProgramBuilder program(r, src);
|
|
|
|
const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
|
|
|
|
REPORTER_ASSERT(r, main);
|
|
|
|
|
|
|
|
skvm::Builder b;
|
2021-12-06 17:02:20 +00:00
|
|
|
SkSL::ProgramToSkVM(*program, *main, &b, /*debugTrace=*/nullptr, /*uniforms=*/{});
|
2021-01-07 19:38:08 +00:00
|
|
|
skvm::Program p = b.done();
|
|
|
|
|
|
|
|
float xs[] = { -2.0f, 0.0f, 3.0f, -1.0f };
|
2021-01-11 18:16:28 +00:00
|
|
|
p.eval(4, xs);
|
2021-01-07 19:38:08 +00:00
|
|
|
|
|
|
|
REPORTER_ASSERT(r, xs[0] == -2.0f);
|
|
|
|
REPORTER_ASSERT(r, xs[1] == 1.0f);
|
|
|
|
REPORTER_ASSERT(r, xs[2] == 4.0f);
|
|
|
|
REPORTER_ASSERT(r, xs[3] == -1.0f);
|
|
|
|
}
|
|
|
|
|
2020-10-16 00:41:20 +00:00
|
|
|
DEF_TEST(SkSLInterpreterEarlyReturn, r) {
|
2021-01-06 21:36:56 +00:00
|
|
|
// Test early returns with divergent control flow
|
2020-10-16 00:41:20 +00:00
|
|
|
const char* src = "float main(float x, float y) { if (x < y) { return x; } return y; }";
|
|
|
|
|
2021-01-06 21:36:56 +00:00
|
|
|
ProgramBuilder program(r, src);
|
2020-10-16 00:41:20 +00:00
|
|
|
|
2021-01-06 21:36:56 +00:00
|
|
|
const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
|
|
|
|
REPORTER_ASSERT(r, main);
|
2020-10-16 00:41:20 +00:00
|
|
|
|
2021-01-06 21:36:56 +00:00
|
|
|
skvm::Builder b;
|
2021-12-06 17:02:20 +00:00
|
|
|
SkSL::ProgramToSkVM(*program, *main, &b, /*debugTrace=*/nullptr, /*uniforms=*/{});
|
2021-01-06 21:36:56 +00:00
|
|
|
skvm::Program p = b.done();
|
2020-10-16 00:41:20 +00:00
|
|
|
|
|
|
|
float xs[] = { 1.0f, 3.0f },
|
|
|
|
ys[] = { 2.0f, 2.0f };
|
|
|
|
float rets[2];
|
2021-01-11 18:16:28 +00:00
|
|
|
p.eval(2, xs, ys, rets);
|
2021-01-06 21:36:56 +00:00
|
|
|
|
2020-10-16 00:41:20 +00:00
|
|
|
REPORTER_ASSERT(r, rets[0] == 1.0f);
|
2021-01-06 21:36:56 +00:00
|
|
|
REPORTER_ASSERT(r, rets[1] == 2.0f);
|
2020-10-16 00:41:20 +00:00
|
|
|
}
|
|
|
|
|
2019-05-14 20:47:30 +00:00
|
|
|
DEF_TEST(SkSLInterpreterFunctions, r) {
|
|
|
|
const char* src =
|
|
|
|
"float sqr(float x) { return x * x; }\n"
|
|
|
|
"float sub(float x, float y) { return x - y; }\n"
|
2019-07-09 18:17:23 +00:00
|
|
|
"float main(float x) { return sub(sqr(x), x); }\n"
|
2019-05-14 20:47:30 +00:00
|
|
|
|
|
|
|
// Different signatures
|
2020-02-27 18:36:57 +00:00
|
|
|
"float dot(float2 a, float2 b) { return a.x*b.x + a.y*b.y; }\n"
|
|
|
|
"float dot(float3 a, float3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; }\n"
|
2019-05-14 20:47:30 +00:00
|
|
|
"float dot3_test(float x) { return dot(float3(x, x + 1, x + 2), float3(1, -1, 2)); }\n"
|
2019-07-09 18:17:23 +00:00
|
|
|
"float dot2_test(float x) { return dot(float2(x, x + 1), float2(1, -1)); }\n";
|
2019-05-14 20:47:30 +00:00
|
|
|
|
2021-01-11 15:39:58 +00:00
|
|
|
ProgramBuilder program(r, src);
|
2019-05-14 20:47:30 +00:00
|
|
|
|
2021-01-11 15:39:58 +00:00
|
|
|
auto sub = SkSL::Program_GetFunction(*program, "sub");
|
|
|
|
auto sqr = SkSL::Program_GetFunction(*program, "sqr");
|
|
|
|
auto main = SkSL::Program_GetFunction(*program, "main");
|
|
|
|
auto tan = SkSL::Program_GetFunction(*program, "tan");
|
|
|
|
auto dot3 = SkSL::Program_GetFunction(*program, "dot3_test");
|
|
|
|
auto dot2 = SkSL::Program_GetFunction(*program, "dot2_test");
|
2019-05-14 20:47:30 +00:00
|
|
|
|
|
|
|
REPORTER_ASSERT(r, sub);
|
|
|
|
REPORTER_ASSERT(r, sqr);
|
|
|
|
REPORTER_ASSERT(r, main);
|
2021-01-11 15:39:58 +00:00
|
|
|
REPORTER_ASSERT(r, !tan); // Getting a non-existent function should return nullptr
|
2019-05-14 20:47:30 +00:00
|
|
|
REPORTER_ASSERT(r, dot3);
|
|
|
|
REPORTER_ASSERT(r, dot2);
|
|
|
|
|
2021-01-11 15:39:58 +00:00
|
|
|
auto test_fn = [&](const SkSL::FunctionDefinition* fn, float in, float expected) {
|
|
|
|
skvm::Builder b;
|
2021-12-06 17:02:20 +00:00
|
|
|
SkSL::ProgramToSkVM(*program, *fn, &b, /*debugTrace=*/nullptr, /*uniforms=*/{});
|
2021-01-11 15:39:58 +00:00
|
|
|
skvm::Program p = b.done();
|
2019-05-14 20:47:30 +00:00
|
|
|
|
2021-01-11 15:39:58 +00:00
|
|
|
float out = 0.0f;
|
2021-01-11 18:16:28 +00:00
|
|
|
p.eval(1, &in, &out);
|
2021-01-11 15:39:58 +00:00
|
|
|
REPORTER_ASSERT(r, out == expected);
|
|
|
|
};
|
2020-01-22 15:31:55 +00:00
|
|
|
|
2021-01-11 15:39:58 +00:00
|
|
|
test_fn(main, 3.0f, 6.0f);
|
|
|
|
test_fn(dot3, 3.0f, 9.0f);
|
|
|
|
test_fn(dot2, 3.0f, -1.0f);
|
2020-02-06 15:49:38 +00:00
|
|
|
}
|
|
|
|
|
2019-06-20 19:41:34 +00:00
|
|
|
DEF_TEST(SkSLInterpreterOutParams, r) {
|
|
|
|
test(r,
|
|
|
|
"void oneAlpha(inout half4 color) { color.a = 1; }"
|
|
|
|
"void main(inout half4 color) { oneAlpha(color); }",
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 1);
|
|
|
|
test(r,
|
2020-04-02 15:38:40 +00:00
|
|
|
"half2 tricky(half x, half y, inout half2 color, half z) {"
|
2019-06-20 19:41:34 +00:00
|
|
|
" color.xy = color.yx;"
|
|
|
|
" return half2(x + y, z);"
|
|
|
|
"}"
|
|
|
|
"void main(inout half4 color) {"
|
2020-04-02 15:38:40 +00:00
|
|
|
" half2 t = tricky(1, 2, color.rb, 5);"
|
2019-06-20 19:41:34 +00:00
|
|
|
" color.ga = t;"
|
|
|
|
"}",
|
2020-04-02 15:38:40 +00:00
|
|
|
1, 2, 3, 4, 3, 3, 1, 5);
|
2019-06-20 19:41:34 +00:00
|
|
|
}
|
|
|
|
|
2020-09-29 17:20:04 +00:00
|
|
|
DEF_TEST(SkSLInterpreterSwizzleSingleLvalue, r) {
|
|
|
|
test(r,
|
|
|
|
"void main(inout half4 color) { color.xywz = half4(1,2,3,4); }",
|
|
|
|
0, 0, 0, 0, 1, 2, 4, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterSwizzleDoubleLvalue, r) {
|
|
|
|
test(r,
|
|
|
|
"void main(inout half4 color) { color.xywz.yxzw = half4(1,2,3,4); }",
|
|
|
|
0, 0, 0, 0, 2, 1, 4, 3);
|
|
|
|
}
|
|
|
|
|
2021-01-25 18:51:57 +00:00
|
|
|
DEF_TEST(SkSLInterpreterSwizzleIndexLvalue, r) {
|
|
|
|
const char* src = R"(
|
|
|
|
void main(inout half4 color) {
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
color.wzyx[i] += half(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)";
|
|
|
|
test(r, src, 0, 0, 0, 0, 3, 2, 1, 0);
|
|
|
|
}
|
|
|
|
|
2019-05-24 16:46:34 +00:00
|
|
|
DEF_TEST(SkSLInterpreterMathFunctions, r) {
|
2019-07-24 21:02:39 +00:00
|
|
|
float value[4], expected[4];
|
|
|
|
|
2020-04-02 15:38:40 +00:00
|
|
|
value[0] = 0.0f; expected[0] = 0.0f;
|
|
|
|
test(r, "float main(float x) { return sin(x); }", value, expected);
|
|
|
|
test(r, "float main(float x) { return tan(x); }", value, expected);
|
2019-07-24 21:02:39 +00:00
|
|
|
|
|
|
|
value[0] = 0.0f; expected[0] = 1.0f;
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float main(float x) { return cos(x); }", value, expected);
|
2019-05-24 16:46:34 +00:00
|
|
|
|
2019-07-24 21:02:39 +00:00
|
|
|
value[0] = 25.0f; expected[0] = 5.0f;
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float main(float x) { return sqrt(x); }", value, expected);
|
2019-05-24 16:46:34 +00:00
|
|
|
|
2019-07-24 21:02:39 +00:00
|
|
|
value[0] = 90.0f; expected[0] = sk_float_degrees_to_radians(value[0]);
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float main(float x) { return radians(x); }", value, expected);
|
2019-05-24 16:46:34 +00:00
|
|
|
|
2019-07-24 21:02:39 +00:00
|
|
|
value[0] = 1.0f; value[1] = -1.0f;
|
|
|
|
expected[0] = 1.0f / SK_FloatSqrt2; expected[1] = -1.0f / SK_FloatSqrt2;
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float2 main(float2 x) { return normalize(x); }", value, expected);
|
2019-05-24 16:46:34 +00:00
|
|
|
}
|
|
|
|
|
2019-06-20 18:54:15 +00:00
|
|
|
DEF_TEST(SkSLInterpreterVoidFunction, r) {
|
|
|
|
test(r,
|
|
|
|
"half x; void foo() { x = 1.0; }"
|
|
|
|
"void main(inout half4 color) { foo(); color.r = x; }",
|
|
|
|
0, 0, 0, 0, 1, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
2019-05-24 16:46:34 +00:00
|
|
|
DEF_TEST(SkSLInterpreterMix, r) {
|
2019-06-14 14:17:16 +00:00
|
|
|
float value, expected;
|
2019-05-24 16:46:34 +00:00
|
|
|
|
|
|
|
value = 0.5f; expected = 0.0f;
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float main(float x) { return mix(-10, 10, x); }", &value, &expected);
|
2019-05-24 16:46:34 +00:00
|
|
|
value = 0.75f; expected = 5.0f;
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float main(float x) { return mix(-10, 10, x); }", &value, &expected);
|
2019-05-24 16:46:34 +00:00
|
|
|
value = 2.0f; expected = 30.0f;
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float main(float x) { return mix(-10, 10, x); }", &value, &expected);
|
2019-05-24 16:46:34 +00:00
|
|
|
|
2019-06-14 14:17:16 +00:00
|
|
|
float valueVectors[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f },
|
|
|
|
expectedVector[] = { 3.0f, 4.0f, 5.0f, 6.0f };
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float4 main(float4 x, float4 y) { return mix(x, y, 0.5); }", valueVectors,
|
2019-05-24 16:46:34 +00:00
|
|
|
expectedVector);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterCross, r) {
|
2019-06-14 14:17:16 +00:00
|
|
|
float args[] = { 1.0f, 4.0f, -6.0f, -2.0f, 7.0f, -3.0f };
|
2020-01-22 19:31:21 +00:00
|
|
|
SkV3 cross = SkV3::Cross({args[0], args[1], args[2]},
|
|
|
|
{args[3], args[4], args[5]});
|
|
|
|
float expected[] = { cross.x, cross.y, cross.z };
|
2019-09-27 14:25:57 +00:00
|
|
|
test(r, "float3 main(float3 x, float3 y) { return cross(x, y); }", args, expected);
|
2019-05-24 16:46:34 +00:00
|
|
|
}
|
2020-01-22 21:59:21 +00:00
|
|
|
|
2019-07-18 17:20:04 +00:00
|
|
|
DEF_TEST(SkSLInterpreterInverse, r) {
|
|
|
|
{
|
|
|
|
SkMatrix m;
|
|
|
|
m.setRotate(30).postScale(1, 2);
|
|
|
|
float args[4] = { m[0], m[3], m[1], m[4] };
|
|
|
|
SkAssertResult(m.invert(&m));
|
|
|
|
float expt[4] = { m[0], m[3], m[1], m[4] };
|
2020-01-22 21:59:21 +00:00
|
|
|
test(r, "float2x2 main(float2x2 m) { return inverse(m); }", args, expt, false);
|
2019-07-18 17:20:04 +00:00
|
|
|
}
|
|
|
|
{
|
|
|
|
SkMatrix m;
|
|
|
|
m.setRotate(30).postScale(1, 2).postTranslate(1, 2);
|
|
|
|
float args[9] = { m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8] };
|
|
|
|
SkAssertResult(m.invert(&m));
|
|
|
|
float expt[9] = { m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8] };
|
2020-01-22 21:59:21 +00:00
|
|
|
test(r, "float3x3 main(float3x3 m) { return inverse(m); }", args, expt, false);
|
2019-07-18 17:20:04 +00:00
|
|
|
}
|
|
|
|
{
|
|
|
|
float args[16], expt[16];
|
|
|
|
// just some crazy thing that is invertible
|
2020-01-22 19:31:21 +00:00
|
|
|
SkM44 m = {1, 2, 3, 4, 1, 2, 0, 3, 1, 0, 1, 4, 1, 3, 2, 0};
|
|
|
|
m.getColMajor(args);
|
2019-07-18 17:20:04 +00:00
|
|
|
SkAssertResult(m.invert(&m));
|
2020-01-22 21:59:21 +00:00
|
|
|
m.getColMajor(expt);
|
|
|
|
test(r, "float4x4 main(float4x4 m) { return inverse(m); }", args, expt, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterDot, r) {
|
|
|
|
float args[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };
|
|
|
|
float expected = args[0] * args[2] +
|
|
|
|
args[1] * args[3];
|
|
|
|
test(r, "float main(float2 x, float2 y) { return dot(x, y); }", args, &expected);
|
|
|
|
|
|
|
|
expected = args[0] * args[3] +
|
|
|
|
args[1] * args[4] +
|
|
|
|
args[2] * args[5];
|
|
|
|
test(r, "float main(float3 x, float3 y) { return dot(x, y); }", args, &expected);
|
|
|
|
|
|
|
|
expected = args[0] * args[4] +
|
|
|
|
args[1] * args[5] +
|
|
|
|
args[2] * args[6] +
|
|
|
|
args[3] * args[7];
|
|
|
|
test(r, "float main(float4 x, float4 y) { return dot(x, y); }", args, &expected);
|
|
|
|
}
|
|
|
|
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
class ExternalSqrt : public SkSL::ExternalFunction {
|
2020-01-22 21:59:21 +00:00
|
|
|
public:
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
ExternalSqrt(const char* name, SkSL::Compiler& compiler)
|
2021-01-11 19:22:36 +00:00
|
|
|
: INHERITED(name, *compiler.context().fTypes.fFloat)
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
, fCompiler(compiler) {}
|
2020-01-22 21:59:21 +00:00
|
|
|
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
int callParameterCount() const override { return 1; }
|
2020-01-22 21:59:21 +00:00
|
|
|
|
|
|
|
void getCallParameterTypes(const SkSL::Type** outTypes) const override {
|
2021-01-11 19:22:36 +00:00
|
|
|
outTypes[0] = fCompiler.context().fTypes.fFloat.get();
|
2020-01-22 21:59:21 +00:00
|
|
|
}
|
|
|
|
|
2021-01-11 22:04:29 +00:00
|
|
|
void call(skvm::Builder* b,
|
|
|
|
skvm::F32* arguments,
|
|
|
|
skvm::F32* outResult,
|
|
|
|
skvm::I32 mask) const override {
|
|
|
|
outResult[0] = sqrt(arguments[0]);
|
|
|
|
}
|
|
|
|
|
2020-01-22 21:59:21 +00:00
|
|
|
private:
|
|
|
|
SkSL::Compiler& fCompiler;
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
using INHERITED = SkSL::ExternalFunction;
|
2020-01-22 21:59:21 +00:00
|
|
|
};
|
|
|
|
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
DEF_TEST(SkSLInterpreterExternalFunction, r) {
|
2021-11-19 15:59:59 +00:00
|
|
|
SkSL::ShaderCaps caps;
|
2020-11-18 20:38:39 +00:00
|
|
|
SkSL::Compiler compiler(&caps);
|
2020-01-22 21:59:21 +00:00
|
|
|
SkSL::Program::Settings settings;
|
2021-09-30 16:31:30 +00:00
|
|
|
const char* src = "float main() { return externalSqrt(25); }";
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
std::vector<std::unique_ptr<SkSL::ExternalFunction>> externalFunctions;
|
2021-09-30 16:31:30 +00:00
|
|
|
externalFunctions.push_back(std::make_unique<ExternalSqrt>("externalSqrt", compiler));
|
2021-05-18 14:12:58 +00:00
|
|
|
settings.fExternalFunctions = &externalFunctions;
|
2020-09-23 17:55:20 +00:00
|
|
|
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
|
2022-02-02 21:51:18 +00:00
|
|
|
SkSL::ProgramKind::kGeneric, std::string(src), settings);
|
2020-01-22 21:59:21 +00:00
|
|
|
REPORTER_ASSERT(r, program);
|
2021-01-11 22:04:29 +00:00
|
|
|
|
|
|
|
const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
|
|
|
|
|
|
|
|
skvm::Builder b;
|
2021-12-06 17:02:20 +00:00
|
|
|
SkSL::ProgramToSkVM(*program, *main, &b, /*debugTrace=*/nullptr, /*uniforms=*/{});
|
2021-01-11 22:04:29 +00:00
|
|
|
skvm::Program p = b.done();
|
|
|
|
|
|
|
|
float out;
|
|
|
|
p.eval(1, &out);
|
|
|
|
REPORTER_ASSERT(r, out == 5.0);
|
2020-01-22 21:59:21 +00:00
|
|
|
}
|
|
|
|
|
2021-01-11 22:04:29 +00:00
|
|
|
class ExternalTable : public SkSL::ExternalFunction {
|
2020-01-22 21:59:21 +00:00
|
|
|
public:
|
2021-01-11 22:04:29 +00:00
|
|
|
ExternalTable(const char* name, SkSL::Compiler& compiler, skvm::Uniforms* uniforms)
|
|
|
|
: INHERITED(name, *compiler.context().fTypes.fFloat)
|
|
|
|
, fCompiler(compiler)
|
|
|
|
, fTable{1, 2, 4, 8} {
|
|
|
|
fAddr = uniforms->pushPtr(fTable);
|
|
|
|
}
|
2020-04-02 15:38:40 +00:00
|
|
|
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
int callParameterCount() const override { return 1; }
|
2020-04-02 15:38:40 +00:00
|
|
|
|
2020-01-22 21:59:21 +00:00
|
|
|
void getCallParameterTypes(const SkSL::Type** outTypes) const override {
|
2021-01-11 22:04:29 +00:00
|
|
|
outTypes[0] = fCompiler.context().fTypes.fFloat.get();
|
2020-01-22 21:59:21 +00:00
|
|
|
}
|
2020-04-02 15:38:40 +00:00
|
|
|
|
2021-01-11 22:04:29 +00:00
|
|
|
void call(skvm::Builder* b,
|
|
|
|
skvm::F32* arguments,
|
|
|
|
skvm::F32* outResult,
|
|
|
|
skvm::I32 mask) const override {
|
|
|
|
skvm::I32 index = skvm::trunc(arguments[0] * 4);
|
|
|
|
index = max(0, min(index, 3));
|
|
|
|
outResult[0] = b->gatherF(fAddr, index);
|
2020-01-22 21:59:21 +00:00
|
|
|
}
|
2020-04-02 15:38:40 +00:00
|
|
|
|
2020-01-22 21:59:21 +00:00
|
|
|
private:
|
|
|
|
SkSL::Compiler& fCompiler;
|
2021-01-11 22:04:29 +00:00
|
|
|
skvm::Uniform fAddr;
|
|
|
|
float fTable[4];
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
using INHERITED = SkSL::ExternalFunction;
|
2020-01-22 21:59:21 +00:00
|
|
|
};
|
2020-04-02 15:38:40 +00:00
|
|
|
|
2021-01-11 22:04:29 +00:00
|
|
|
DEF_TEST(SkSLInterpreterExternalTable, r) {
|
2021-11-19 15:59:59 +00:00
|
|
|
SkSL::ShaderCaps caps;
|
2020-11-18 20:38:39 +00:00
|
|
|
SkSL::Compiler compiler(&caps);
|
2020-01-22 21:59:21 +00:00
|
|
|
SkSL::Program::Settings settings;
|
2020-09-23 17:55:20 +00:00
|
|
|
const char* src =
|
2021-01-11 22:04:29 +00:00
|
|
|
"float4 main() { return float4(table(2), table(-1), table(0.4), table(0.6)); }";
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
std::vector<std::unique_ptr<SkSL::ExternalFunction>> externalFunctions;
|
2021-01-11 22:04:29 +00:00
|
|
|
|
|
|
|
skvm::Builder b;
|
|
|
|
skvm::Uniforms u(b.uniform(), 0);
|
|
|
|
|
|
|
|
externalFunctions.push_back(std::make_unique<ExternalTable>("table", compiler, &u));
|
2021-05-18 14:12:58 +00:00
|
|
|
settings.fExternalFunctions = &externalFunctions;
|
2020-09-23 17:55:20 +00:00
|
|
|
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
|
2022-02-02 21:51:18 +00:00
|
|
|
SkSL::ProgramKind::kGeneric, std::string(src), settings);
|
2020-01-22 21:59:21 +00:00
|
|
|
REPORTER_ASSERT(r, program);
|
2021-01-11 22:04:29 +00:00
|
|
|
|
|
|
|
const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
|
|
|
|
|
2021-12-06 17:02:20 +00:00
|
|
|
SkSL::ProgramToSkVM(*program, *main, &b, /*debugTrace=*/nullptr, /*uniforms=*/{});
|
2021-01-11 22:04:29 +00:00
|
|
|
skvm::Program p = b.done();
|
|
|
|
|
|
|
|
float out[4];
|
|
|
|
p.eval(1, u.buf.data(), &out[0], &out[1], &out[2], &out[3]);
|
|
|
|
REPORTER_ASSERT(r, out[0] == 8.0);
|
|
|
|
REPORTER_ASSERT(r, out[1] == 1.0);
|
|
|
|
REPORTER_ASSERT(r, out[2] == 2.0);
|
|
|
|
REPORTER_ASSERT(r, out[3] == 4.0);
|
2019-05-17 20:31:21 +00:00
|
|
|
}
|
2021-11-18 15:47:10 +00:00
|
|
|
|
|
|
|
DEF_TEST(SkSLInterpreterTrace, r) {
|
2021-11-19 15:59:59 +00:00
|
|
|
SkSL::ShaderCaps caps;
|
2021-11-18 15:47:10 +00:00
|
|
|
SkSL::Compiler compiler(&caps);
|
|
|
|
SkSL::Program::Settings settings;
|
|
|
|
settings.fOptimize = false;
|
|
|
|
|
|
|
|
constexpr const char kSrc[] =
|
2021-11-20 01:01:44 +00:00
|
|
|
R"(bool less_than(float left, int right) {
|
|
|
|
bool comparison = left < float(right);
|
Improve redundant trace_var elimination.
Previously, we would avoid emitting redundant trace_vars by checking to
see if the slot is being assigned to the exact same Var.ID. However,
this had the potential to eliminate useful trace_vars:
- At the start of execution, slots all contain 0. Code which explicitly
assigned a zero into a slot would not be shown in a trace. (So things
like `color = half4(0,1,0,1)` would only emit traces for color.ga.)
- A function call's parameter slots are reused every time it is called,
so calling a function twice would only emit traces for the parameters
that aren't the same Val.ID as the previous call.
- A VarDeclaration inside a loop reuses its slot each time through the
loop, even though conceptually it's a "new" variable.
We now track a slot's "written-to" status. At the start of execution,
no slots have been "written-to". These slots will always emit a
trace_var opcode (fixing the first issue). Also, issuing a function
call or declaring a variable will reset the "written-to" status of the
associated slots (fixing the second and third issues).
When the debugger is not in use, the written-to field is unused.
Change-Id: I482a86cb6e90d0f85dd2a161e984f212782a7b4d
Bug: skia:12614
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/473776
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
2021-11-18 21:36:29 +00:00
|
|
|
if (comparison) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2021-11-18 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
2021-12-07 14:54:51 +00:00
|
|
|
float2 a[2];
|
2021-11-20 01:01:44 +00:00
|
|
|
for (float loop = 10; loop <= 30; loop += 10) {
|
2021-12-07 14:54:51 +00:00
|
|
|
half4 v = half4(loop, loop+1, loop+2, loop+3);
|
|
|
|
float2x2 m = float2x2(v);
|
|
|
|
a[0] = float2(loop, loop+1); a[1] = float2(loop+2, loop+3);
|
2021-11-18 15:47:10 +00:00
|
|
|
bool function_result = less_than(loop, 20);
|
|
|
|
}
|
|
|
|
return 40;
|
|
|
|
}
|
|
|
|
)";
|
|
|
|
skvm::Builder b;
|
|
|
|
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::ProgramKind::kGeneric,
|
2022-02-02 21:51:18 +00:00
|
|
|
std::string(kSrc), settings);
|
2021-11-18 15:47:10 +00:00
|
|
|
REPORTER_ASSERT(r, program);
|
|
|
|
|
|
|
|
const SkSL::FunctionDefinition* main = SkSL::Program_GetFunction(*program, "main");
|
2021-12-06 17:02:20 +00:00
|
|
|
SkSL::SkVMDebugTrace debugTrace;
|
|
|
|
SkSL::ProgramToSkVM(*program, *main, &b, &debugTrace, /*uniforms=*/{});
|
2021-11-18 15:47:10 +00:00
|
|
|
skvm::Program p = b.done();
|
|
|
|
REPORTER_ASSERT(r, p.nargs() == 1);
|
|
|
|
|
2021-12-03 16:12:29 +00:00
|
|
|
int result;
|
|
|
|
p.eval(1, &result);
|
2021-11-18 15:47:10 +00:00
|
|
|
|
2021-12-03 20:13:55 +00:00
|
|
|
SkDynamicMemoryWStream streamDump;
|
2021-12-06 17:02:20 +00:00
|
|
|
debugTrace.dump(&streamDump);
|
2021-12-03 20:13:55 +00:00
|
|
|
|
|
|
|
sk_sp<SkData> dataDump = streamDump.detachAsData();
|
2022-02-01 20:31:57 +00:00
|
|
|
std::string_view trace{static_cast<const char*>(dataDump->data()), dataDump->size()};
|
2021-11-18 15:47:10 +00:00
|
|
|
|
|
|
|
REPORTER_ASSERT(r, result == 40);
|
2021-12-03 16:12:29 +00:00
|
|
|
REPORTER_ASSERT(r, trace ==
|
2021-12-03 20:13:55 +00:00
|
|
|
R"($0 = [main].result (int, L10)
|
2021-12-07 14:54:51 +00:00
|
|
|
$1 = a[0] (float2 : slot 1/2, L11)
|
|
|
|
$2 = a[0] (float2 : slot 2/2, L11)
|
|
|
|
$3 = a[1] (float2 : slot 1/2, L11)
|
|
|
|
$4 = a[1] (float2 : slot 2/2, L11)
|
|
|
|
$5 = loop (float, L12)
|
|
|
|
$6 = v (float4 : slot 1/4, L13)
|
|
|
|
$7 = v (float4 : slot 2/4, L13)
|
|
|
|
$8 = v (float4 : slot 3/4, L13)
|
|
|
|
$9 = v (float4 : slot 4/4, L13)
|
|
|
|
$10 = m (float2x2 : slot 1/4, L14)
|
|
|
|
$11 = m (float2x2 : slot 2/4, L14)
|
|
|
|
$12 = m (float2x2 : slot 3/4, L14)
|
|
|
|
$13 = m (float2x2 : slot 4/4, L14)
|
|
|
|
$14 = function_result (bool, L16)
|
|
|
|
$15 = [less_than].result (bool, L1)
|
|
|
|
$16 = left (float, L1)
|
|
|
|
$17 = right (int, L1)
|
|
|
|
$18 = comparison (bool, L2)
|
2021-12-03 20:13:55 +00:00
|
|
|
F0 = int main()
|
|
|
|
F1 = bool less_than(float left, int right)
|
|
|
|
|
|
|
|
enter int main()
|
2021-12-14 23:43:35 +00:00
|
|
|
scope +1
|
|
|
|
line 11
|
|
|
|
a[0].x = 0
|
|
|
|
a[0].y = 0
|
|
|
|
a[1].x = 0
|
|
|
|
a[1].y = 0
|
|
|
|
line 12
|
|
|
|
scope +1
|
|
|
|
loop = 10
|
|
|
|
scope +1
|
|
|
|
line 13
|
|
|
|
v.x = 10
|
|
|
|
v.y = 11
|
|
|
|
v.z = 12
|
|
|
|
v.w = 13
|
|
|
|
line 14
|
|
|
|
m[0][0] = 10
|
|
|
|
m[0][1] = 11
|
|
|
|
m[1][0] = 12
|
|
|
|
m[1][1] = 13
|
|
|
|
line 15
|
|
|
|
a[0].x = 10
|
|
|
|
a[0].y = 11
|
|
|
|
line 15
|
|
|
|
a[1].x = 12
|
|
|
|
a[1].y = 13
|
|
|
|
line 16
|
|
|
|
enter bool less_than(float left, int right)
|
|
|
|
left = 10
|
|
|
|
right = 20
|
|
|
|
scope +1
|
|
|
|
line 2
|
|
|
|
comparison = true
|
|
|
|
line 3
|
|
|
|
scope +1
|
|
|
|
line 4
|
|
|
|
[less_than].result = true
|
|
|
|
scope -1
|
|
|
|
scope -1
|
|
|
|
exit bool less_than(float left, int right)
|
|
|
|
function_result = true
|
|
|
|
scope -1
|
|
|
|
line 12
|
|
|
|
loop = 20
|
|
|
|
scope +1
|
|
|
|
line 13
|
|
|
|
v.x = 20
|
|
|
|
v.y = 21
|
|
|
|
v.z = 22
|
|
|
|
v.w = 23
|
|
|
|
line 14
|
|
|
|
m[0][0] = 20
|
|
|
|
m[0][1] = 21
|
|
|
|
m[1][0] = 22
|
|
|
|
m[1][1] = 23
|
|
|
|
line 15
|
|
|
|
a[0].x = 20
|
|
|
|
a[0].y = 21
|
|
|
|
line 15
|
|
|
|
a[1].x = 22
|
|
|
|
a[1].y = 23
|
|
|
|
line 16
|
|
|
|
enter bool less_than(float left, int right)
|
|
|
|
left = 20
|
|
|
|
right = 20
|
|
|
|
scope +1
|
|
|
|
line 2
|
|
|
|
comparison = false
|
|
|
|
line 3
|
|
|
|
scope +1
|
|
|
|
line 6
|
|
|
|
[less_than].result = false
|
|
|
|
scope -1
|
|
|
|
scope -1
|
|
|
|
exit bool less_than(float left, int right)
|
|
|
|
function_result = false
|
|
|
|
scope -1
|
|
|
|
line 12
|
|
|
|
loop = 30
|
|
|
|
scope +1
|
|
|
|
line 13
|
|
|
|
v.x = 30
|
|
|
|
v.y = 31
|
|
|
|
v.z = 32
|
|
|
|
v.w = 33
|
|
|
|
line 14
|
|
|
|
m[0][0] = 30
|
|
|
|
m[0][1] = 31
|
|
|
|
m[1][0] = 32
|
|
|
|
m[1][1] = 33
|
|
|
|
line 15
|
|
|
|
a[0].x = 30
|
|
|
|
a[0].y = 31
|
|
|
|
line 15
|
|
|
|
a[1].x = 32
|
|
|
|
a[1].y = 33
|
|
|
|
line 16
|
|
|
|
enter bool less_than(float left, int right)
|
|
|
|
left = 30
|
|
|
|
right = 20
|
|
|
|
scope +1
|
|
|
|
line 2
|
|
|
|
comparison = false
|
|
|
|
line 3
|
|
|
|
scope +1
|
|
|
|
line 6
|
|
|
|
[less_than].result = false
|
|
|
|
scope -1
|
|
|
|
scope -1
|
|
|
|
exit bool less_than(float left, int right)
|
|
|
|
function_result = false
|
|
|
|
scope -1
|
|
|
|
line 12
|
|
|
|
scope -1
|
|
|
|
line 18
|
|
|
|
[main].result = 40
|
|
|
|
scope -1
|
2021-11-18 15:47:10 +00:00
|
|
|
exit int main()
|
2021-12-03 20:13:55 +00:00
|
|
|
)", "Trace output does not match expectation:\n%.*s\n", (int)trace.size(), trace.data());
|
2021-11-18 15:47:10 +00:00
|
|
|
}
|