Interpreter: Refactor interface and lifetime management

Interpreter is now just a namespace with Run and Disassemble. This hides
all of the implementation details. In addition, the interpreter only used
the Program because of a few details in FunctionDeclarations - scrape that
when constructing a ByteCodeFunction, and we don't need to keep the entire
Program alive, just the ByteCode. Adjust tests to ensure that this works.

Change-Id: I61efe4fe986476afedbd295d3d55b2a326fea4e3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/219521
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2019-06-07 13:00:23 -04:00 committed by Skia Commit-Bot
parent b0632faa59
commit 8016441e20
8 changed files with 165 additions and 235 deletions

View File

@ -479,10 +479,10 @@ public:
REFLECTED(SkInterpreterAffector, SkParticleAffector)
void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
fInterpreter->setInputs((SkSL::Interpreter::Value*)&params);
for (int i = 0; i < count; ++i) {
fRandomValue->setRandom(&ps[i].fRandom);
fInterpreter->run(*fMain, (SkSL::Interpreter::Value*)&ps[i].fAge, nullptr);
SkSL::Interpreter::Run(fByteCode.get(), fMain, (SkSL::Interpreter::Value*)&ps[i].fAge,
nullptr, (SkSL::Interpreter::Value*)&params, 2);
}
}
@ -501,7 +501,7 @@ private:
SkString fCode;
// Cached
std::unique_ptr<SkSL::Interpreter> fInterpreter;
std::unique_ptr<SkSL::ByteCode> fByteCode;
std::unique_ptr<SkRandomExternalValue> fRandomValue;
SkSL::ByteCodeFunction* fMain;
@ -523,11 +523,8 @@ private:
return;
}
// These will be replaced with the real inputs in onApply, before running
SkParticleUpdateParams defaultInputs = { 0.0f, 0.0f, 0 };
fMain = byteCode->fFunctions[0].get();
fInterpreter.reset(new SkSL::Interpreter(std::move(program), std::move(byteCode),
(SkSL::Interpreter::Value*)&defaultInputs));
fByteCode = std::move(byteCode);
fRandomValue = std::move(rand);
}
};

View File

@ -404,12 +404,14 @@ public:
rec.fPipeline->append(SkRasterPipeline::callback, ctx);
} else {
struct InterpreterCtx : public SkRasterPipeline_CallbackCtx {
std::unique_ptr<SkSL::ByteCode> byteCode;
SkSL::ByteCodeFunction* main;
std::unique_ptr<SkSL::Interpreter> interpreter;
const void* inputs;
int ninputs;
};
auto ctx = rec.fAlloc->make<InterpreterCtx>();
ctx->inputs = fInputs->data();
ctx->ninputs = fInputs->size() / 4;
SkSL::Compiler c;
std::unique_ptr<SkSL::Program> prog =
c.convertProgram(SkSL::Program::kPipelineStage_Kind,
@ -419,16 +421,15 @@ public:
SkDebugf("%s\n", c.errorText().c_str());
SkASSERT(false);
}
std::unique_ptr<SkSL::ByteCode> byteCode = c.toByteCode(*prog);
ctx->main = byteCode->fFunctions[0].get();
ctx->interpreter.reset(new SkSL::Interpreter(std::move(prog), std::move(byteCode),
(SkSL::Interpreter::Value*) ctx->inputs));
ctx->byteCode = c.toByteCode(*prog);
ctx->main = ctx->byteCode->fFunctions[0].get();
ctx->fn = [](SkRasterPipeline_CallbackCtx* arg, int active_pixels) {
auto ctx = (InterpreterCtx*)arg;
for (int i = 0; i < active_pixels; i++) {
ctx->interpreter->run(*ctx->main,
(SkSL::Interpreter::Value*) (ctx->rgba + i * 4),
nullptr);
SkSL::Interpreter::Run(ctx->byteCode.get(), ctx->main,
(SkSL::Interpreter::Value*) (ctx->rgba + i * 4),
nullptr, (SkSL::Interpreter::Value*)ctx->inputs,
ctx->ninputs);
}
};
rec.fPipeline->append(SkRasterPipeline::callback, ctx);

View File

@ -8,7 +8,7 @@
#ifndef SKSL_BYTECODE
#define SKSL_BYTECODE
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
#include "src/sksl/SkSLString.h"
#include <memory>
#include <vector>
@ -128,11 +128,17 @@ enum class ByteCodeInstruction : uint16_t {
#undef VECTOR
struct ByteCodeFunction {
ByteCodeFunction(const FunctionDeclaration* declaration)
: fDeclaration(*declaration) {}
ByteCodeFunction(const FunctionDeclaration* declaration);
struct Parameter {
int fSlotCount;
bool fIsOutParameter;
};
SkSL::String fName;
std::vector<Parameter> fParameters;
int fParameterCount;
const FunctionDeclaration& fDeclaration;
int fParameterCount = 0;
int fLocalCount = 0;
// TODO: Compute this value analytically. For now, just pick an arbitrary value that we probably
// won't overflow.
@ -149,7 +155,7 @@ struct ByteCode {
const ByteCodeFunction* getFunction(const char* name) const {
for (const auto& f : fFunctions) {
if (f->fDeclaration.fName == name) {
if (f->fName == name) {
return f.get();
}
}

View File

@ -56,6 +56,7 @@ bool ByteCodeGenerator::generateCode() {
return false;
}
fOutput->fFunctions.push_back(std::move(f));
fFunctions.push_back(&(FunctionDefinition&)e);
break;
}
case ProgramElement::kVar_Kind: {
@ -90,15 +91,11 @@ bool ByteCodeGenerator::generateCode() {
std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
fFunction = &f;
std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
fParameterCount = 0;
for (const auto& p : f.fDeclaration.fParameters) {
fParameterCount += SlotCount(p->fType);
}
fParameterCount = result->fParameterCount;
fCode = &result->fCode;
this->writeStatement(*f.fBody);
this->write(ByteCodeInstruction::kReturn);
this->write8(0);
result->fParameterCount = fParameterCount;
result->fLocalCount = fLocals.size();
const Type& returnType = f.fDeclaration.fReturnType;
if (returnType != *fContext.fVoid_Type) {
@ -1149,4 +1146,14 @@ void ByteCodeGenerator::writeStatement(const Statement& s) {
}
}
ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
: fName(declaration->fName) {
fParameterCount = 0;
for (const auto& p : declaration->fParameters) {
int slots = ByteCodeGenerator::SlotCount(p->fType);
fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
fParameterCount += slots;
}
}
}

View File

@ -145,7 +145,7 @@ private:
bool set() {
size_t idx;
const auto& functions(fGenerator.fOutput->fFunctions);
const auto& functions(fGenerator.fFunctions);
for (idx = 0; idx < functions.size(); ++idx) {
if (fFunction.matches(functions[idx]->fDeclaration)) {
break;
@ -294,6 +294,7 @@ private:
std::stack<std::vector<DeferredLocation>> fBreakTargets;
std::vector<const FunctionDefinition*> fFunctions;
std::vector<DeferredCallTarget> fCallTargets;
int fParameterCount;

View File

@ -8,72 +8,15 @@
#ifndef SKSL_STANDALONE
#include "include/core/SkPoint3.h"
#include "src/core/SkRasterPipeline.h"
#include "src/sksl/SkSLByteCode.h"
#include "src/sksl/SkSLByteCodeGenerator.h"
#include "src/sksl/SkSLExternalValue.h"
#include "src/sksl/SkSLInterpreter.h"
#include "src/sksl/ir/SkSLBinaryExpression.h"
#include "src/sksl/ir/SkSLExpressionStatement.h"
#include "src/sksl/ir/SkSLForStatement.h"
#include "src/sksl/ir/SkSLFunctionCall.h"
#include "src/sksl/ir/SkSLFunctionReference.h"
#include "src/sksl/ir/SkSLIfStatement.h"
#include "src/sksl/ir/SkSLIndexExpression.h"
#include "src/sksl/ir/SkSLPostfixExpression.h"
#include "src/sksl/ir/SkSLPrefixExpression.h"
#include "src/sksl/ir/SkSLProgram.h"
#include "src/sksl/ir/SkSLStatement.h"
#include "src/sksl/ir/SkSLTernaryExpression.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
#include "src/sksl/ir/SkSLVarDeclarationsStatement.h"
#include "src/sksl/ir/SkSLVariableReference.h"
#include <vector>
namespace SkSL {
static constexpr int UNINITIALIZED = 0xDEADBEEF;
Interpreter::Interpreter(std::unique_ptr<Program> program,
std::unique_ptr<ByteCode> byteCode,
Interpreter::Value inputs[])
: fProgram(std::move(program))
, fByteCode(std::move(byteCode))
, fGlobals(fByteCode->fGlobalCount, UNINITIALIZED) {
this->setInputs(inputs);
}
void Interpreter::setInputs(Interpreter::Value inputs[]) {
for (uint8_t slot : fByteCode->fInputSlots) {
fGlobals[slot] = *inputs++;
}
}
void Interpreter::run(const ByteCodeFunction& f, Interpreter::Value args[],
Interpreter::Value* outReturn) {
#ifdef TRACE
this->disassemble(f);
#endif
Value smallStack[128];
std::unique_ptr<Value[]> largeStack;
Value* stack = smallStack;
if ((int) SK_ARRAY_COUNT(smallStack) < f.fStackCount) {
largeStack.reset(new Value[f.fStackCount]);
stack = largeStack.get();
}
if (f.fParameterCount) {
memcpy(stack, args, f.fParameterCount * sizeof(Value));
}
this->innerRun(f, stack, outReturn);
for (const Variable* p : f.fDeclaration.fParameters) {
const int nvalues = ByteCodeGenerator::SlotCount(p->fType);
if (p->fModifiers.fFlags & Modifiers::kOut_Flag) {
memcpy(args, stack, nvalues * sizeof(Value));
}
args += nvalues;
stack += nvalues;
}
}
namespace Interpreter {
template <typename T>
static T unaligned_load(const void* ptr) {
@ -280,10 +223,10 @@ static const uint8_t* disassemble_instruction(const uint8_t* ip) {
return ip;
}
void Interpreter::disassemble(const ByteCodeFunction& f) {
const uint8_t* ip = f.fCode.data();
while (ip < f.fCode.data() + f.fCode.size()) {
printf("%d: ", (int) (ip - f.fCode.data()));
void Disassemble(const ByteCodeFunction* f) {
const uint8_t* ip = f->fCode.data();
while (ip < f->fCode.data() + f->fCode.size()) {
printf("%d: ", (int) (ip - f->fCode.data()));
ip = disassemble_instruction(ip);
printf("\n");
}
@ -361,13 +304,14 @@ static float mix(float start, float end, float t) {
return start * (1 - t) + end * t;
}
void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outReturn) {
Value* sp = stack + f.fParameterCount + f.fLocalCount - 1;
void innerRun(const ByteCode* byteCode, const ByteCodeFunction* f, Value* stack, Value* outReturn,
Value globals[], int globalCount) {
Value* sp = stack + f->fParameterCount + f->fLocalCount - 1;
auto POP = [&] { SkASSERT(sp >= stack); return *(sp--); };
auto PUSH = [&](Value v) { SkASSERT(sp + 1 >= stack); *(++sp) = v; };
const uint8_t* code = f.fCode.data();
const uint8_t* code = f->fCode.data();
const uint8_t* ip = code;
std::vector<StackFrame> frames;
@ -395,7 +339,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
// stack to point at the first parameter, and our sp to point past those parameters
// (plus space for locals).
int target = READ8();
const ByteCodeFunction* fun = fByteCode->fFunctions[target].get();
const ByteCodeFunction* fun = byteCode->fFunctions[target].get();
frames.push_back({ code, ip, stack });
ip = code = fun->fCode.data();
stack = sp - fun->fParameterCount + 1;
@ -407,7 +351,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
int argumentCount = READ8();
int returnCount = READ8();
int target = READ8();
ExternalValue* v = fByteCode->fExternalValues[target];
ExternalValue* v = byteCode->fExternalValues[target];
sp -= argumentCount - 1;
Value tmp[4];
@ -502,10 +446,10 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
sp += (int)inst - (int)ByteCodeInstruction::kLoad + 1;
break;
case ByteCodeInstruction::kLoadGlobal4: sp[4] = fGlobals[*ip + 3];
case ByteCodeInstruction::kLoadGlobal3: sp[3] = fGlobals[*ip + 2];
case ByteCodeInstruction::kLoadGlobal2: sp[2] = fGlobals[*ip + 1];
case ByteCodeInstruction::kLoadGlobal : sp[1] = fGlobals[*ip + 0];
case ByteCodeInstruction::kLoadGlobal4: sp[4] = globals[*ip + 3];
case ByteCodeInstruction::kLoadGlobal3: sp[3] = globals[*ip + 2];
case ByteCodeInstruction::kLoadGlobal2: sp[2] = globals[*ip + 1];
case ByteCodeInstruction::kLoadGlobal : sp[1] = globals[*ip + 0];
++ip;
sp += (int)inst -
(int)ByteCodeInstruction::kLoadGlobal + 1;
@ -522,8 +466,8 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
case ByteCodeInstruction::kLoadExtendedGlobal: {
int count = READ8();
int src = POP().fSigned;
SkASSERT(src + count <= (int) fGlobals.size());
memcpy(sp + 1, &fGlobals[src], count * sizeof(Value));
SkASSERT(src + count <= globalCount);
memcpy(sp + 1, &globals[src], count * sizeof(Value));
sp += count;
break;
}
@ -540,10 +484,10 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
case ByteCodeInstruction::kLoadSwizzleGlobal: {
int src = READ8();
SkASSERT(src < (int) fGlobals.size());
int count = READ8();
for (int i = 0; i < count; ++i) {
PUSH(fGlobals[src + *(ip + i)]);
SkASSERT(src + *(ip + i) < globalCount);
PUSH(globals[src + *(ip + i)]);
}
ip += count;
break;
@ -668,7 +612,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
case ByteCodeInstruction::kReadExternal3: // fall through
case ByteCodeInstruction::kReadExternal4: {
int src = READ8();
fByteCode->fExternalValues[src]->read(sp + 1);
byteCode->fExternalValues[src]->read(sp + 1);
sp += (int) inst - (int) ByteCodeInstruction::kReadExternal + 1;
break;
}
@ -723,10 +667,10 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
++ip;
break;
case ByteCodeInstruction::kStoreGlobal4: fGlobals[*ip + 3] = POP();
case ByteCodeInstruction::kStoreGlobal3: fGlobals[*ip + 2] = POP();
case ByteCodeInstruction::kStoreGlobal2: fGlobals[*ip + 1] = POP();
case ByteCodeInstruction::kStoreGlobal : fGlobals[*ip + 0] = POP();
case ByteCodeInstruction::kStoreGlobal4: globals[*ip + 3] = POP();
case ByteCodeInstruction::kStoreGlobal3: globals[*ip + 2] = POP();
case ByteCodeInstruction::kStoreGlobal2: globals[*ip + 1] = POP();
case ByteCodeInstruction::kStoreGlobal : globals[*ip + 0] = POP();
++ip;
break;
@ -740,8 +684,8 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
case ByteCodeInstruction::kStoreExtendedGlobal: {
int count = READ8();
int target = POP().fSigned;
SkASSERT(target + count <= (int) fGlobals.size());
memcpy(&fGlobals[target], sp - count + 1, count * sizeof(Value));
SkASSERT(target + count <= globalCount);
memcpy(&globals[target], sp - count + 1, count * sizeof(Value));
sp -= count;
break;
}
@ -760,7 +704,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
int target = READ8();
int count = READ8();
for (int i = count - 1; i >= 0; --i) {
fGlobals[target + *(ip + i)] = POP();
globals[target + *(ip + i)] = POP();
}
ip += count;
break;
@ -778,7 +722,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
int target = POP().fSigned;
int count = READ8();
for (int i = count - 1; i >= 0; --i) {
fGlobals[target + *(ip + i)] = POP();
globals[target + *(ip + i)] = POP();
}
ip += count;
break;
@ -806,7 +750,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
case ByteCodeInstruction::kWriteExternal4: {
int count = (int) inst - (int) ByteCodeInstruction::kWriteExternal + 1;
int target = READ8();
fByteCode->fExternalValues[target]->write(sp - count + 1);
byteCode->fExternalValues[target]->write(sp - count + 1);
sp -= count;
break;
}
@ -825,6 +769,46 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
}
}
} // namespace
void Run(const ByteCode* byteCode, const ByteCodeFunction* f, Value args[], Value* outReturn,
Value uniforms[], int uniformCount) {
#ifdef TRACE
disassemble(f);
#endif
Value smallStack[128];
std::unique_ptr<Value[]> largeStack;
Value* stack = smallStack;
if ((int)SK_ARRAY_COUNT(smallStack) < f->fStackCount) {
largeStack.reset(new Value[f->fStackCount]);
stack = largeStack.get();
}
if (f->fParameterCount) {
memcpy(stack, args, f->fParameterCount * sizeof(Value));
}
SkASSERT(uniformCount == (int)byteCode->fInputSlots.size());
Value smallGlobals[32];
std::unique_ptr<Value[]> largeGlobals;
Value* globals = smallGlobals;
if ((int)SK_ARRAY_COUNT(smallGlobals) < byteCode->fGlobalCount) {
largeGlobals.reset(new Value[byteCode->fGlobalCount]);
globals = largeGlobals.get();
}
for (uint8_t slot : byteCode->fInputSlots) {
globals[slot] = *uniforms++;
}
innerRun(byteCode, f, stack, outReturn, globals, byteCode->fGlobalCount);
for (const auto& p : f->fParameters) {
if (p.fIsOutParameter) {
memcpy(args, stack, p.fSlotCount * sizeof(Value));
}
args += p.fSlotCount;
stack += p.fSlotCount;
}
}
} // namespace Interpreter
} // namespace SkSL
#endif

View File

@ -8,22 +8,15 @@
#ifndef SKSL_INTERPRETER
#define SKSL_INTERPRETER
#include "src/sksl/SkSLByteCode.h"
#include "src/sksl/ir/SkSLAppendStage.h"
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLFunctionCall.h"
#include "src/sksl/ir/SkSLFunctionDefinition.h"
#include "src/sksl/ir/SkSLProgram.h"
#include "src/sksl/ir/SkSLStatement.h"
#include <stack>
#include "src/sksl/SkSLDefines.h"
namespace SkSL {
class Interpreter {
typedef int StackIndex;
struct ByteCode;
struct ByteCodeFunction;
namespace Interpreter {
public:
union Value {
Value() {}
@ -45,43 +38,20 @@ public:
bool fBool;
};
enum TypeKind {
kFloat_TypeKind,
kInt_TypeKind,
kBool_TypeKind
};
/**
* 'inputs' contains the values of global 'in' variables in source order.
*/
Interpreter(std::unique_ptr<Program> program, std::unique_ptr<ByteCode> byteCode,
Value inputs[] = nullptr);
/**
* Invokes the specified function with the given arguments. 'out' and 'inout' parameters will
* result in the 'args' array being modified. The return value is stored in 'outReturn' (may be
* null, in which case the return value is discarded).
*/
void run(const ByteCodeFunction& f, Value args[], Value* outReturn);
/**
* Updates the global inputs.
*/
void setInputs(Value inputs[]);
void Run(const ByteCode*, const ByteCodeFunction*, Value args[], Value* outReturn,
Value uniforms[], int uniformCount);
/**
* Print bytecode disassembly to stdout.
*/
void disassemble(const ByteCodeFunction&);
private:
void innerRun(const ByteCodeFunction& f, Value* stack, Value* outReturn);
void Disassemble(const ByteCodeFunction*);
std::unique_ptr<Program> fProgram;
std::unique_ptr<ByteCode> fByteCode;
std::vector<Value> fGlobals;
};
} // namespace
} // namespace Interpreter
} // namespace SkSL
#endif

View File

@ -23,16 +23,16 @@ void test(skiatest::Reporter* r, const char* src, SkSL::Interpreter::Value* in,
REPORTER_ASSERT(r, program);
if (program) {
std::unique_ptr<SkSL::ByteCode> byteCode = compiler.toByteCode(*program);
program.reset();
REPORTER_ASSERT(r, !compiler.errorCount());
if (compiler.errorCount() > 0) {
printf("%s\n%s", src, compiler.errorText().c_str());
return;
}
SkSL::ByteCodeFunction* main = byteCode->fFunctions[0].get();
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode));
std::unique_ptr<SkSL::Interpreter::Value[]> out =
std::unique_ptr<SkSL::Interpreter::Value[]>(new SkSL::Interpreter::Value[expectedCount]);
interpreter.run(*main, in, out.get());
SkSL::Interpreter::Run(byteCode.get(), main, in, out.get(), nullptr, 0);
bool valid = !memcmp(out.get(), expected, sizeof(SkSL::Interpreter::Value) * expectedCount);
if (!valid) {
printf("for program: %s\n", src);
@ -49,7 +49,7 @@ void test(skiatest::Reporter* r, const char* src, SkSL::Interpreter::Value* in,
separator = ", ";
}
printf(")\n");
interpreter.disassemble(*main);
SkSL::Interpreter::Disassemble(main);
}
REPORTER_ASSERT(r, valid);
} else {
@ -67,22 +67,23 @@ void test(skiatest::Reporter* r, const char* src, float inR, float inG, float in
REPORTER_ASSERT(r, program);
if (program) {
std::unique_ptr<SkSL::ByteCode> byteCode = compiler.toByteCode(*program);
program.reset();
REPORTER_ASSERT(r, !compiler.errorCount());
if (compiler.errorCount() > 0) {
printf("%s\n%s", src, compiler.errorText().c_str());
return;
}
SkSL::ByteCodeFunction* main = byteCode->fFunctions[0].get();
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode));
float inoutColor[4] = { inR, inG, inB, inA };
interpreter.run(*main, (SkSL::Interpreter::Value*) inoutColor, nullptr);
SkSL::Interpreter::Run(byteCode.get(), main, (SkSL::Interpreter::Value*) inoutColor,
nullptr, nullptr, 0);
if (inoutColor[0] != expectedR || inoutColor[1] != expectedG ||
inoutColor[2] != expectedB || inoutColor[3] != expectedA) {
printf("for program: %s\n", src);
printf(" expected (%f, %f, %f, %f), but received (%f, %f, %f, %f)\n", expectedR,
expectedG, expectedB, expectedA, inoutColor[0], inoutColor[1], inoutColor[2],
inoutColor[3]);
interpreter.disassemble(*main);
SkSL::Interpreter::Disassemble(main);
}
REPORTER_ASSERT(r, inoutColor[0] == expectedR);
REPORTER_ASSERT(r, inoutColor[1] == expectedG);
@ -416,45 +417,6 @@ DEF_TEST(SkSLInterpreterGeneric, r) {
(SkSL::Interpreter::Value*) expected2);
}
DEF_TEST(SkSLInterpreterSetInputs, r) {
const char* src = R"(
layout(ctype=float) in uniform float x;
float main(float y) { return x + y; }
)";
SkSL::Compiler compiler;
SkSL::Program::Settings settings;
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
SkSL::Program::kGeneric_Kind,
SkSL::String(src), settings);
REPORTER_ASSERT(r, program);
std::unique_ptr<SkSL::ByteCode> byteCode = compiler.toByteCode(*program);
REPORTER_ASSERT(r, !compiler.errorCount());
SkSL::ByteCodeFunction* main = byteCode->fFunctions[0].get();
float x = 1.0f;
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode),
(SkSL::Interpreter::Value*)&x);
float out = 0.0f;
float in = 2.0f;
interpreter.run(*main, (SkSL::Interpreter::Value*)&in, (SkSL::Interpreter::Value*)&out);
REPORTER_ASSERT(r, out == 3.0f);
// External updates should be ignored
x = 3.0f;
out = 0.0f;
interpreter.run(*main, (SkSL::Interpreter::Value*)&in, (SkSL::Interpreter::Value*)&out);
REPORTER_ASSERT(r, out == 3.0f);
// Updating inputs should affect subsequent calls to run
out = 0.0f;
interpreter.setInputs((SkSL::Interpreter::Value*)&x);
interpreter.run(*main, (SkSL::Interpreter::Value*)&in, (SkSL::Interpreter::Value*)&out);
REPORTER_ASSERT(r, out == 5.0f);
}
DEF_TEST(SkSLInterpreterCompound, r) {
struct RectAndColor { SkIRect fRect; SkColor4f fColor; };
struct ManyRects { int fNumRects; RectAndColor fRects[4]; };
@ -522,24 +484,23 @@ DEF_TEST(SkSLInterpreterCompound, r) {
SkIRect gRects[4] = { { 1,2,3,4 }, { 5,6,7,8 }, { 9,10,11,12 }, { 13,14,15,16 } };
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode),
(SkSL::Interpreter::Value*)gRects);
{
SkIRect in = SkIRect::MakeXYWH(10, 10, 20, 30);
int out = 0;
interpreter.run(*rect_height,
(SkSL::Interpreter::Value*)&in,
(SkSL::Interpreter::Value*)&out);
SkSL::Interpreter::Run(byteCode.get(), rect_height,
(SkSL::Interpreter::Value*)&in,
(SkSL::Interpreter::Value*)&out,
(SkSL::Interpreter::Value*)gRects, 16);
REPORTER_ASSERT(r, out == 30);
}
{
int in[2] = { 15, 25 };
RectAndColor out;
interpreter.run(*make_blue_rect,
(SkSL::Interpreter::Value*)in,
(SkSL::Interpreter::Value*)&out);
SkSL::Interpreter::Run(byteCode.get(), make_blue_rect,
(SkSL::Interpreter::Value*)in,
(SkSL::Interpreter::Value*)&out,
(SkSL::Interpreter::Value*)gRects, 16);
REPORTER_ASSERT(r, out.fRect.width() == 15);
REPORTER_ASSERT(r, out.fRect.height() == 25);
SkColor4f blue = { 0.0f, 1.0f, 0.0f, 1.0f };
@ -549,18 +510,20 @@ 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;
interpreter.run(*median,
(SkSL::Interpreter::Value*)in,
(SkSL::Interpreter::Value*)&out);
SkSL::Interpreter::Run(byteCode.get(), median,
(SkSL::Interpreter::Value*)in,
(SkSL::Interpreter::Value*)&out,
(SkSL::Interpreter::Value*)gRects, 16);
REPORTER_ASSERT(r, out == 8);
}
{
float in[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
float out[8] = { 0 };
interpreter.run(*sums,
(SkSL::Interpreter::Value*)in,
(SkSL::Interpreter::Value*)out);
SkSL::Interpreter::Run(byteCode.get(), sums,
(SkSL::Interpreter::Value*)in,
(SkSL::Interpreter::Value*)out,
(SkSL::Interpreter::Value*)gRects, 16);
for (int i = 0; i < 8; ++i) {
REPORTER_ASSERT(r, out[i] == static_cast<float>((i + 1) * (i + 2) / 2));
}
@ -569,9 +532,10 @@ DEF_TEST(SkSLInterpreterCompound, r) {
{
int in = 2;
SkIRect out = SkIRect::MakeEmpty();
interpreter.run(*get_rect,
(SkSL::Interpreter::Value*)&in,
(SkSL::Interpreter::Value*)&out);
SkSL::Interpreter::Run(byteCode.get(), get_rect,
(SkSL::Interpreter::Value*)&in,
(SkSL::Interpreter::Value*)&out,
(SkSL::Interpreter::Value*)gRects, 16);
REPORTER_ASSERT(r, out == gRects[2]);
}
@ -579,9 +543,10 @@ DEF_TEST(SkSLInterpreterCompound, r) {
ManyRects in;
memset(&in, 0, sizeof(in));
in.fNumRects = 2;
interpreter.run(*fill_rects,
(SkSL::Interpreter::Value*)&in,
nullptr);
SkSL::Interpreter::Run(byteCode.get(), fill_rects,
(SkSL::Interpreter::Value*)&in,
nullptr,
(SkSL::Interpreter::Value*)gRects, 16);
ManyRects expected;
memset(&expected, 0, sizeof(expected));
expected.fNumRects = 2;
@ -635,21 +600,24 @@ DEF_TEST(SkSLInterpreterFunctions, r) {
REPORTER_ASSERT(r, dot2);
REPORTER_ASSERT(r, fib);
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode), nullptr);
float out = 0.0f;
float in = 3.0f;
interpreter.run(*main, (SkSL::Interpreter::Value*)&in, (SkSL::Interpreter::Value*)&out);
SkSL::Interpreter::Run(byteCode.get(), main, (SkSL::Interpreter::Value*)&in,
(SkSL::Interpreter::Value*)&out, nullptr, 0);
REPORTER_ASSERT(r, out = 6.0f);
interpreter.run(*dot3, (SkSL::Interpreter::Value*)&in, (SkSL::Interpreter::Value*)&out);
SkSL::Interpreter::Run(byteCode.get(), dot3, (SkSL::Interpreter::Value*)&in,
(SkSL::Interpreter::Value*)&out, nullptr, 0);
REPORTER_ASSERT(r, out = 9.0f);
interpreter.run(*dot2, (SkSL::Interpreter::Value*)&in, (SkSL::Interpreter::Value*)&out);
SkSL::Interpreter::Run(byteCode.get(), dot2, (SkSL::Interpreter::Value*)&in,
(SkSL::Interpreter::Value*)&out, nullptr, 0);
REPORTER_ASSERT(r, out = -1.0f);
int fibIn = 6;
int fibOut = 0;
interpreter.run(*fib, (SkSL::Interpreter::Value*)&fibIn, (SkSL::Interpreter::Value*)&fibOut);
SkSL::Interpreter::Run(byteCode.get(), fib, (SkSL::Interpreter::Value*)&fibIn,
(SkSL::Interpreter::Value*)&fibOut, nullptr, 0);
REPORTER_ASSERT(r, fibOut == 13);
}
@ -830,9 +798,8 @@ DEF_TEST(SkSLInterpreterExternalValues, r) {
return;
}
SkSL::ByteCodeFunction* main = byteCode->fFunctions[0].get();
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode));
SkSL::Interpreter::Value out;
interpreter.run(*main, nullptr, &out);
SkSL::Interpreter::Run(byteCode.get(), main, nullptr, &out, nullptr, 0);
REPORTER_ASSERT(r, out.fFloat == 66.0);
REPORTER_ASSERT(r, outValue == 152);
} else {
@ -864,9 +831,8 @@ DEF_TEST(SkSLInterpreterExternalValuesVector, r) {
return;
}
SkSL::ByteCodeFunction* main = byteCode->fFunctions[0].get();
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode));
SkSL::Interpreter::Value out;
interpreter.run(*main, nullptr, &out);
SkSL::Interpreter::Run(byteCode.get(), main, nullptr, &out, nullptr, 0);
REPORTER_ASSERT(r, value[0] == 2);
REPORTER_ASSERT(r, value[1] == 4);
REPORTER_ASSERT(r, value[2] == 6);
@ -931,9 +897,8 @@ DEF_TEST(SkSLInterpreterExternalValuesCall, r) {
return;
}
SkSL::ByteCodeFunction* main = byteCode->fFunctions[0].get();
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode));
SkSL::Interpreter::Value out;
interpreter.run(*main, nullptr, &out);
SkSL::Interpreter::Run(byteCode.get(), main, nullptr, &out, nullptr, 0);
REPORTER_ASSERT(r, out.fFloat == 5.0);
} else {
printf("%s\n%s", src, compiler.errorText().c_str());
@ -1000,9 +965,8 @@ DEF_TEST(SkSLInterpreterExternalValuesVectorCall, r) {
return;
}
SkSL::ByteCodeFunction* main = byteCode->fFunctions[0].get();
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode));
SkSL::Interpreter::Value out[4];
interpreter.run(*main, nullptr, out);
SkSL::Interpreter::Run(byteCode.get(), main, nullptr, out, nullptr, 0);
REPORTER_ASSERT(r, out[0].fFloat == 1.0);
REPORTER_ASSERT(r, out[1].fFloat == 2.0);
REPORTER_ASSERT(r, out[2].fFloat == 3.0);