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:
parent
b0632faa59
commit
8016441e20
@ -479,10 +479,10 @@ public:
|
||||
REFLECTED(SkInterpreterAffector, SkParticleAffector)
|
||||
|
||||
void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
|
||||
fInterpreter->setInputs((SkSL::Interpreter::Value*)¶ms);
|
||||
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*)¶ms, 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);
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user