diff --git a/src/sksl/SkSLVMGenerator.cpp b/src/sksl/SkSLVMGenerator.cpp index a75adafd7b..763404d848 100644 --- a/src/sksl/SkSLVMGenerator.cpp +++ b/src/sksl/SkSLVMGenerator.cpp @@ -1445,13 +1445,11 @@ skvm::Color ProgramToSkVM(const Program& program, bool ProgramToSkVM(const Program& program, const FunctionDefinition& function, skvm::Builder* b, + SkSpan uniforms, SkVMSignature* outSignature) { SkVMSignature ignored, *signature = outSignature ? outSignature : &ignored; - skvm::Ptr uniforms = b->uniform(); - (void)uniforms; - std::vector argPtrs; std::vector argVals; @@ -1474,7 +1472,7 @@ bool ProgramToSkVM(const Program& program, } skvm::Coord zeroCoord = {b->splat(0.0f), b->splat(0.0f)}; - SkVMGenerator generator(program, b, /*uniforms=*/{}, /*device=*/zeroCoord, /*local=*/zeroCoord, + SkVMGenerator generator(program, b, uniforms, /*device=*/zeroCoord, /*local=*/zeroCoord, /*sampleChild=*/{}); generator.writeFunction(function, argVals, returnVals); diff --git a/src/sksl/SkSLVMGenerator.h b/src/sksl/SkSLVMGenerator.h index 577721d029..61825a99c3 100644 --- a/src/sksl/SkSLVMGenerator.h +++ b/src/sksl/SkSLVMGenerator.h @@ -38,21 +38,23 @@ struct SkVMSignature { }; /* - * Converts 'function' to skvm instructions in 'builder'. Always adds one arg for uniforms, then - * one per value in the parameter list, and finally one per value in the return type. For example: + * Converts 'function' to skvm instructions in 'builder'. Always adds one arg per value in the + * parameter list, then one per value in the return type. For example: * - * uniform float u; uniform float v; * float2 fn(float2 a, float b) { ... } * * ... is mapped so that it can be called as: * - * p.eval(N, uniforms, &a.x, &a.y, &b, &return.x, &return.y); + * p.eval(N, &a.x, &a.y, &b, &return.x, &return.y); * * The number of parameter and return slots (pointers) is placed in 'outSignature', if provided. + * If the program declares any uniforms, 'uniforms' should contain the IDs of each individual value + * (eg, one ID per component of a vector). */ bool ProgramToSkVM(const Program& program, const FunctionDefinition& function, skvm::Builder* b, + SkSpan uniforms, SkVMSignature* outSignature = nullptr); const FunctionDefinition* Program_GetFunction(const Program& program, const char* function); diff --git a/tests/SkSLInterpreterTest.cpp b/tests/SkSLInterpreterTest.cpp index f53c9432cc..92622d22d5 100644 --- a/tests/SkSLInterpreterTest.cpp +++ b/tests/SkSLInterpreterTest.cpp @@ -109,19 +109,18 @@ void test_skvm(skiatest::Reporter* r, const char* src, float* in, const float* e skvm::Builder b; SkSL::SkVMSignature sig; - SkSL::ProgramToSkVM(*program, *main, &b, &sig); + SkSL::ProgramToSkVM(*program, *main, &b, /*uniforms=*/{}, &sig); skvm::Program p = b.done(); - REPORTER_ASSERT(r, p.nargs() == (int)(1 /*uniforms*/ + sig.fParameterSlots + sig.fReturnSlots)); + REPORTER_ASSERT(r, p.nargs() == (int)(sig.fParameterSlots + sig.fReturnSlots)); auto out = std::make_unique(sig.fReturnSlots); - auto args = std::make_unique(1 + sig.fParameterSlots + sig.fReturnSlots); - args[0] = nullptr; // uniforms + auto args = std::make_unique(sig.fParameterSlots + sig.fReturnSlots); for (size_t i = 0; i < sig.fParameterSlots; ++i) { - args[1+ i] = in + i; + args[i] = in + i; } for (size_t i = 0; i < sig.fReturnSlots; ++i) { - args[1 + sig.fParameterSlots + i] = out.get() + i; + args[sig.fParameterSlots + i] = out.get() + i; } // TODO: Test with and without JIT? @@ -207,12 +206,11 @@ void test_skvm(skiatest::Reporter* r, const char* src, REPORTER_ASSERT(r, main); skvm::Builder b; - SkSL::ProgramToSkVM(*program, *main, &b); + SkSL::ProgramToSkVM(*program, *main, &b, /*uniforms=*/{}); skvm::Program p = b.done(); // TODO: Test with and without JIT? - const void* uniforms = nullptr; - p.eval(1, uniforms, &inR, &inG, &inB, &inA); + p.eval(1, &inR, &inG, &inB, &inA); float actual[4] = { inR, inG, inB, inA }; float expected[4] = { exR, exG, exB, exA }; @@ -597,9 +595,9 @@ DEF_TEST(SkSLInterpreterCompound, r) { " return tempFloats[7];\n" "}\n" - // Uniforms, array-of-structs, dynamic indices + // Uniforms, array-of-structs "uniform Rect gRects[4];\n" - "Rect get_rect(int i) { return gRects[i]; }\n" + "Rect get_rect_2() { return gRects[2]; }\n" // Kitchen sink (swizzles, inout, SoAoS) "struct ManyRects { int numRects; RectAndColor rects[4]; };\n" @@ -611,38 +609,57 @@ DEF_TEST(SkSLInterpreterCompound, r) { " }\n" "}\n"; - GrShaderCaps caps(GrContextOptions{}); - SkSL::Compiler compiler(&caps); - SkSL::Program::Settings settings; - settings.fRemoveDeadFunctions = false; - std::unique_ptr program = compiler.convertProgram(SkSL::Program::kGeneric_Kind, - SkSL::String(src), settings); - REPORTER_ASSERT(r, program); + ProgramBuilder program(r, src); - std::unique_ptr byteCode = compiler.toByteCode(*program); - REPORTER_ASSERT(r, !compiler.errorCount()); - - auto rect_height = byteCode->getFunction("rect_height"), - make_blue_rect = byteCode->getFunction("make_blue_rect"), - median = byteCode->getFunction("median"), - sums = byteCode->getFunction("sums"), - get_rect = byteCode->getFunction("get_rect"), - fill_rects = byteCode->getFunction("fill_rects"); + 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"); SkIRect gRects[4] = { { 1,2,3,4 }, { 5,6,7,8 }, { 9,10,11,12 }, { 13,14,15,16 } }; - const float* fRects = (const float*)gRects; + + auto build = [&](const SkSL::FunctionDefinition* fn) { + skvm::Builder b; + skvm::Ptr uniformPtr = b.uniform(); + skvm::Val uniforms[16]; + for (int i = 0; i < 16; ++i) { + uniforms[i] = b.uniform32(uniformPtr, i * sizeof(int)).id; + } + SkSL::ProgramToSkVM(*program, *fn, &b, uniforms); + 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(base, i * sizeof(float))); + } + } + std::vector fArgs; + }; { SkIRect in = SkIRect::MakeXYWH(10, 10, 20, 30); int out = 0; - SkAssertResult(byteCode->run(rect_height, (float*)&in, 4, (float*)&out, 1, fRects, 16)); + skvm::Program p = build(rect_height); + Args args(gRects); + args.add(&in, 4); + args.add(&out, 1); + p.eval(1, args.fArgs.data()); REPORTER_ASSERT(r, out == 30); } { int in[2] = { 15, 25 }; RectAndColor out; - SkAssertResult(byteCode->run(make_blue_rect, (float*)in, 2, (float*)&out, 8, fRects, 16)); + skvm::Program p = build(make_blue_rect); + Args args(gRects); + args.add(&in, 2); + args.add(&out, 8); + p.eval(1, args.fArgs.data()); REPORTER_ASSERT(r, out.fRect.width() == 15); REPORTER_ASSERT(r, out.fRect.height() == 25); SkColor4f blue = { 0.0f, 1.0f, 0.0f, 1.0f }; @@ -652,29 +669,44 @@ DEF_TEST(SkSLInterpreterCompound, r) { { int in[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; int out = 0; - SkAssertResult(byteCode->run(median, (float*)in, 15, (float*)&out, 1, fRects, 16)); + skvm::Program p = build(median); + Args args(gRects); + args.add(&in, 15); + args.add(&out, 1); + p.eval(1, args.fArgs.data()); REPORTER_ASSERT(r, out == 8); } - { + // TODO: Doesn't work until SkVM generator supports loops + if (false) { float in[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; float out = 0; - SkAssertResult(byteCode->run(sums, in, 8, &out, 1, fRects, 16)); + skvm::Program p = build(sums); + Args args(gRects); + args.add(&in, 8); + args.add(&out, 1); + p.eval(1, args.fArgs.data()); REPORTER_ASSERT(r, out == static_cast((7 + 1) * (7 + 2) / 2)); } { - int in = 2; SkIRect out = SkIRect::MakeEmpty(); - SkAssertResult(byteCode->run(get_rect, (float*)&in, 1, (float*)&out, 4, fRects, 16)); + skvm::Program p = build(get_rect_2); + Args args(gRects); + args.add(&out, 4); + p.eval(1, args.fArgs.data()); REPORTER_ASSERT(r, out == gRects[2]); } - { + // TODO: Doesn't work until SkVM generator supports loops + if (false) { ManyRects in; memset(&in, 0, sizeof(in)); in.fNumRects = 2; - SkAssertResult(byteCode->run(fill_rects, (float*)&in, 33, nullptr, 0, fRects, 16)); + skvm::Program p = build(fill_rects); + Args args(gRects); + args.add(&in, 33); + p.eval(1, args.fArgs.data()); ManyRects expected; memset(&expected, 0, sizeof(expected)); expected.fNumRects = 2; @@ -740,12 +772,11 @@ DEF_TEST(SkSLInterpreterReturnThenCall, r) { REPORTER_ASSERT(r, main); skvm::Builder b; - SkSL::ProgramToSkVM(*program, *main, &b); + SkSL::ProgramToSkVM(*program, *main, &b, /*uniforms=*/{}); skvm::Program p = b.done(); float xs[] = { -2.0f, 0.0f, 3.0f, -1.0f }; - const void* uniforms = nullptr; - p.eval(4, uniforms, xs); + p.eval(4, xs); REPORTER_ASSERT(r, xs[0] == -2.0f); REPORTER_ASSERT(r, xs[1] == 1.0f); @@ -763,14 +794,13 @@ DEF_TEST(SkSLInterpreterEarlyReturn, r) { REPORTER_ASSERT(r, main); skvm::Builder b; - SkSL::ProgramToSkVM(*program, *main, &b); + SkSL::ProgramToSkVM(*program, *main, &b, /*uniforms=*/{}); skvm::Program p = b.done(); float xs[] = { 1.0f, 3.0f }, ys[] = { 2.0f, 2.0f }; float rets[2]; - const void* uniforms = nullptr; - p.eval(2, uniforms, xs, ys, rets); + p.eval(2, xs, ys, rets); REPORTER_ASSERT(r, rets[0] == 1.0f); REPORTER_ASSERT(r, rets[1] == 2.0f); @@ -820,12 +850,11 @@ DEF_TEST(SkSLInterpreterFunctions, r) { auto test_fn = [&](const SkSL::FunctionDefinition* fn, float in, float expected) { skvm::Builder b; - SkSL::ProgramToSkVM(*program, *fn, &b); + SkSL::ProgramToSkVM(*program, *fn, &b, /*uniforms=*/{}); skvm::Program p = b.done(); float out = 0.0f; - const void* uniforms = nullptr; - p.eval(1, uniforms, &in, &out); + p.eval(1, &in, &out); REPORTER_ASSERT(r, out == expected); };