diff options
Diffstat (limited to 'src/sksl/SkSLInterpreter.cpp')
-rw-r--r-- | src/sksl/SkSLInterpreter.cpp | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/src/sksl/SkSLInterpreter.cpp b/src/sksl/SkSLInterpreter.cpp new file mode 100644 index 0000000000..c9b7ceb44c --- /dev/null +++ b/src/sksl/SkSLInterpreter.cpp @@ -0,0 +1,473 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_STANDALONE + +#include "SkSLInterpreter.h" +#include "ir/SkSLBinaryExpression.h" +#include "ir/SkSLExpressionStatement.h" +#include "ir/SkSLForStatement.h" +#include "ir/SkSLFunctionCall.h" +#include "ir/SkSLFunctionReference.h" +#include "ir/SkSLIfStatement.h" +#include "ir/SkSLIndexExpression.h" +#include "ir/SkSLPostfixExpression.h" +#include "ir/SkSLPrefixExpression.h" +#include "ir/SkSLProgram.h" +#include "ir/SkSLStatement.h" +#include "ir/SkSLTernaryExpression.h" +#include "ir/SkSLVarDeclarations.h" +#include "ir/SkSLVarDeclarationsStatement.h" +#include "ir/SkSLVariableReference.h" +#include "SkRasterPipeline.h" +#include "../jumper/SkJumper.h" + +namespace SkSL { + +void Interpreter::run() { + for (const auto& e : fProgram->fElements) { + if (ProgramElement::kFunction_Kind == e->fKind) { + const FunctionDefinition& f = (const FunctionDefinition&) *e; + if ("appendStages" == f.fDeclaration.fName) { + this->run(f); + return; + } + } + } + ASSERT(false); +} + +static int SizeOf(const Type& type) { + return 1; +} + +void Interpreter::run(const FunctionDefinition& f) { + fVars.emplace_back(); + StackIndex current = (StackIndex) fStack.size(); + for (int i = f.fDeclaration.fParameters.size() - 1; i >= 0; --i) { + current -= SizeOf(f.fDeclaration.fParameters[i]->fType); + fVars.back()[f.fDeclaration.fParameters[i]] = current; + } + fCurrentIndex.push_back({ f.fBody.get(), 0 }); + while (fCurrentIndex.size()) { + this->runStatement(); + } +} + +void Interpreter::push(Value value) { + fStack.push_back(value); +} + +Interpreter::Value Interpreter::pop() { + auto iter = fStack.end() - 1; + Value result = *iter; + fStack.erase(iter); + return result; +} + + Interpreter::StackIndex Interpreter::stackAlloc(int count) { + int result = fStack.size(); + for (int i = 0; i < count; ++i) { + fStack.push_back(Value((int) 0xDEADBEEF)); + } + return result; +} + +void Interpreter::runStatement() { + const Statement& stmt = *fCurrentIndex.back().fStatement; + const size_t index = fCurrentIndex.back().fIndex; + fCurrentIndex.pop_back(); + switch (stmt.fKind) { + case Statement::kBlock_Kind: { + const Block& b = (const Block&) stmt; + if (!b.fStatements.size()) { + break; + } + ASSERT(index < b.fStatements.size()); + if (index < b.fStatements.size() - 1) { + fCurrentIndex.push_back({ &b, index + 1 }); + } + fCurrentIndex.push_back({ b.fStatements[index].get(), 0 }); + break; + } + case Statement::kBreak_Kind: + ASSERT(index == 0); + abort(); + case Statement::kContinue_Kind: + ASSERT(index == 0); + abort(); + case Statement::kDiscard_Kind: + ASSERT(index == 0); + abort(); + case Statement::kDo_Kind: + abort(); + case Statement::kExpression_Kind: + ASSERT(index == 0); + this->evaluate(*((const ExpressionStatement&) stmt).fExpression); + break; + case Statement::kFor_Kind: { + ForStatement& f = (ForStatement&) stmt; + switch (index) { + case 0: + // initializer + fCurrentIndex.push_back({ &f, 1 }); + if (f.fInitializer) { + fCurrentIndex.push_back({ f.fInitializer.get(), 0 }); + } + break; + case 1: + // test & body + if (f.fTest && !evaluate(*f.fTest).fBool) { + break; + } else { + fCurrentIndex.push_back({ &f, 2 }); + fCurrentIndex.push_back({ f.fStatement.get(), 0 }); + } + break; + case 2: + // next + if (f.fNext) { + this->evaluate(*f.fNext); + } + fCurrentIndex.push_back({ &f, 1 }); + break; + default: + ASSERT(false); + } + break; + } + case Statement::kGroup_Kind: + abort(); + case Statement::kIf_Kind: { + IfStatement& i = (IfStatement&) stmt; + if (evaluate(*i.fTest).fBool) { + fCurrentIndex.push_back({ i.fIfTrue.get(), 0 }); + } else if (i.fIfFalse) { + fCurrentIndex.push_back({ i.fIfFalse.get(), 0 }); + } + break; + } + case Statement::kNop_Kind: + ASSERT(index == 0); + break; + case Statement::kReturn_Kind: + ASSERT(index == 0); + abort(); + case Statement::kSwitch_Kind: + abort(); + case Statement::kVarDeclarations_Kind: + ASSERT(index == 0); + for (const auto& decl :((const VarDeclarationsStatement&) stmt).fDeclaration->fVars) { + const Variable* var = ((VarDeclaration&) *decl).fVar; + StackIndex pos = this->stackAlloc(SizeOf(var->fType)); + fVars.back()[var] = pos; + if (var->fInitialValue) { + fStack[pos] = this->evaluate(*var->fInitialValue); + } + } + break; + case Statement::kWhile_Kind: + abort(); + default: + abort(); + } +} + +static Interpreter::TypeKind type_kind(const Type& type) { + if (type.fName == "int") { + return Interpreter::kInt_TypeKind; + } else if (type.fName == "float") { + return Interpreter::kFloat_TypeKind; + } + ABORT("unsupported type: %s\n", type.description().c_str()); +} + +Interpreter::StackIndex Interpreter::getLValue(const Expression& expr) { + switch (expr.fKind) { + case Expression::kFieldAccess_Kind: + break; + case Expression::kIndex_Kind: { + const IndexExpression& idx = (const IndexExpression&) expr; + return this->evaluate(*idx.fBase).fInt + this->evaluate(*idx.fIndex).fInt; + } + case Expression::kSwizzle_Kind: + break; + case Expression::kVariableReference_Kind: + ASSERT(fVars.size()); + ASSERT(fVars.back().find(&((VariableReference&) expr).fVariable) != + fVars.back().end()); + return fVars.back()[&((VariableReference&) expr).fVariable]; + case Expression::kTernary_Kind: { + const TernaryExpression& t = (const TernaryExpression&) expr; + return this->getLValue(this->evaluate(*t.fTest).fBool ? *t.fIfTrue : *t.fIfFalse); + } + case Expression::kTypeReference_Kind: + break; + default: + break; + } + ABORT("unsupported lvalue"); +} + +struct CallbackCtx : public SkJumper_CallbackCtx { + Interpreter* fInterpreter; + const FunctionDefinition* fFunction; +}; + +static void do_callback(SkJumper_CallbackCtx* raw, int activePixels) { + CallbackCtx& ctx = (CallbackCtx&) *raw; + for (int i = 0; i < activePixels; ++i) { + ctx.fInterpreter->push(Interpreter::Value(ctx.rgba[i * 4 + 0])); + ctx.fInterpreter->push(Interpreter::Value(ctx.rgba[i * 4 + 1])); + ctx.fInterpreter->push(Interpreter::Value(ctx.rgba[i * 4 + 2])); + ctx.fInterpreter->run(*ctx.fFunction); + ctx.read_from[i * 4 + 2] = ctx.fInterpreter->pop().fFloat; + ctx.read_from[i * 4 + 1] = ctx.fInterpreter->pop().fFloat; + ctx.read_from[i * 4 + 0] = ctx.fInterpreter->pop().fFloat; + } +} + +void Interpreter::appendStage(const AppendStage& a) { + switch (a.fStage) { + case SkRasterPipeline::matrix_4x5: { + ASSERT(a.fArguments.size() == 1); + StackIndex transpose = evaluate(*a.fArguments[0]).fInt; + fPipeline.append(SkRasterPipeline::matrix_4x5, &fStack[transpose]); + break; + } + case SkRasterPipeline::callback: { + ASSERT(a.fArguments.size() == 1); + CallbackCtx* ctx = new CallbackCtx(); + ctx->fInterpreter = this; + ctx->fn = do_callback; + for (const auto& e : fProgram->fElements) { + if (ProgramElement::kFunction_Kind == e->fKind) { + const FunctionDefinition& f = (const FunctionDefinition&) *e; + if (&f.fDeclaration == + ((const FunctionReference&) *a.fArguments[0]).fFunctions[0]) { + ctx->fFunction = &f; + } + } + } + fPipeline.append(SkRasterPipeline::callback, ctx); + break; + } + default: + fPipeline.append(a.fStage); + } +} + +Interpreter::Value Interpreter::call(const FunctionCall& c) { + abort(); +} + +Interpreter::Value Interpreter::evaluate(const Expression& expr) { + switch (expr.fKind) { + case Expression::kAppendStage_Kind: + this->appendStage((const AppendStage&) expr); + return Value((int) 0xDEADBEEF); + case Expression::kBinary_Kind: { + #define ARITHMETIC(op) { \ + Value left = this->evaluate(*b.fLeft); \ + Value right = this->evaluate(*b.fRight); \ + switch (type_kind(b.fLeft->fType)) { \ + case kFloat_TypeKind: \ + return Value(left.fFloat op right.fFloat); \ + case kInt_TypeKind: \ + return Value(left.fInt op right.fInt); \ + default: \ + abort(); \ + } \ + } + #define BITWISE(op) { \ + Value left = this->evaluate(*b.fLeft); \ + Value right = this->evaluate(*b.fRight); \ + switch (type_kind(b.fLeft->fType)) { \ + case kInt_TypeKind: \ + return Value(left.fInt op right.fInt); \ + default: \ + abort(); \ + } \ + } + #define LOGIC(op) { \ + Value left = this->evaluate(*b.fLeft); \ + Value right = this->evaluate(*b.fRight); \ + switch (type_kind(b.fLeft->fType)) { \ + case kFloat_TypeKind: \ + return Value(left.fFloat op right.fFloat); \ + case kInt_TypeKind: \ + return Value(left.fInt op right.fInt); \ + default: \ + abort(); \ + } \ + } + #define COMPOUND_ARITHMETIC(op) { \ + StackIndex left = this->getLValue(*b.fLeft); \ + Value right = this->evaluate(*b.fRight); \ + Value result = fStack[left]; \ + switch (type_kind(b.fLeft->fType)) { \ + case kFloat_TypeKind: \ + result.fFloat op right.fFloat; \ + break; \ + case kInt_TypeKind: \ + result.fInt op right.fInt; \ + break; \ + default: \ + abort(); \ + } \ + fStack[left] = result; \ + return result; \ + } + #define COMPOUND_BITWISE(op) { \ + StackIndex left = this->getLValue(*b.fLeft); \ + Value right = this->evaluate(*b.fRight); \ + Value result = fStack[left]; \ + switch (type_kind(b.fLeft->fType)) { \ + case kInt_TypeKind: \ + result.fInt op right.fInt; \ + break; \ + default: \ + abort(); \ + } \ + fStack[left] = result; \ + return result; \ + } + const BinaryExpression& b = (const BinaryExpression&) expr; + switch (b.fOperator) { + case Token::PLUS: ARITHMETIC(+) + case Token::MINUS: ARITHMETIC(-) + case Token::STAR: ARITHMETIC(*) + case Token::SLASH: ARITHMETIC(/) + case Token::BITWISEAND: BITWISE(&) + case Token::BITWISEOR: BITWISE(|) + case Token::BITWISEXOR: BITWISE(^) + case Token::LT: LOGIC(<) + case Token::GT: LOGIC(>) + case Token::LTEQ: LOGIC(<=) + case Token::GTEQ: LOGIC(>=) + case Token::LOGICALAND: { + Value result = this->evaluate(*b.fLeft); + if (result.fBool) { + result = this->evaluate(*b.fRight); + } + return result; + } + case Token::LOGICALOR: { + Value result = this->evaluate(*b.fLeft); + if (!result.fBool) { + result = this->evaluate(*b.fRight); + } + return result; + } + case Token::EQ: { + StackIndex left = this->getLValue(*b.fLeft); + Value right = this->evaluate(*b.fRight); + fStack[left] = right; + return right; + } + case Token::PLUSEQ: COMPOUND_ARITHMETIC(+=) + case Token::MINUSEQ: COMPOUND_ARITHMETIC(-=) + case Token::STAREQ: COMPOUND_ARITHMETIC(*=) + case Token::SLASHEQ: COMPOUND_ARITHMETIC(/=) + case Token::BITWISEANDEQ: COMPOUND_BITWISE(&=) + case Token::BITWISEOREQ: COMPOUND_BITWISE(|=) + case Token::BITWISEXOREQ: COMPOUND_BITWISE(^=) + default: + ABORT("unsupported operator: %s\n", expr.description().c_str()); + } + break; + } + case Expression::kBoolLiteral_Kind: + return Value(((const BoolLiteral&) expr).fValue); + case Expression::kConstructor_Kind: + break; + case Expression::kIntLiteral_Kind: + return Value((int) ((const IntLiteral&) expr).fValue); + case Expression::kFieldAccess_Kind: + break; + case Expression::kFloatLiteral_Kind: + return Value((float) ((const FloatLiteral&) expr).fValue); + case Expression::kFunctionCall_Kind: + return this->call((const FunctionCall&) expr); + case Expression::kIndex_Kind: { + const IndexExpression& idx = (const IndexExpression&) expr; + StackIndex pos = this->evaluate(*idx.fBase).fInt + + this->evaluate(*idx.fIndex).fInt; + return fStack[pos]; + } + case Expression::kPrefix_Kind: { + const PrefixExpression& p = (const PrefixExpression&) expr; + switch (p.fOperator) { + case Token::MINUS: { + Value base = this->evaluate(*p.fOperand); + switch (type_kind(p.fType)) { + case kFloat_TypeKind: + return Value(-base.fFloat); + case kInt_TypeKind: + return Value(-base.fInt); + default: + abort(); + } + } + case Token::LOGICALNOT: { + Value base = this->evaluate(*p.fOperand); + return Value(!base.fBool); + } + default: + abort(); + } + } + case Expression::kPostfix_Kind: { + const PostfixExpression& p = (const PostfixExpression&) expr; + StackIndex lvalue = this->getLValue(*p.fOperand); + Value result = fStack[lvalue]; + switch (type_kind(p.fType)) { + case kFloat_TypeKind: + if (Token::PLUSPLUS == p.fOperator) { + ++fStack[lvalue].fFloat; + } else { + ASSERT(Token::MINUSMINUS == p.fOperator); + --fStack[lvalue].fFloat; + } + break; + case kInt_TypeKind: + if (Token::PLUSPLUS == p.fOperator) { + ++fStack[lvalue].fInt; + } else { + ASSERT(Token::MINUSMINUS == p.fOperator); + --fStack[lvalue].fInt; + } + break; + default: + abort(); + } + return result; + } + case Expression::kSetting_Kind: + break; + case Expression::kSwizzle_Kind: + break; + case Expression::kVariableReference_Kind: + ASSERT(fVars.size()); + ASSERT(fVars.back().find(&((VariableReference&) expr).fVariable) != + fVars.back().end()); + return fStack[fVars.back()[&((VariableReference&) expr).fVariable]]; + case Expression::kTernary_Kind: { + const TernaryExpression& t = (const TernaryExpression&) expr; + return this->evaluate(this->evaluate(*t.fTest).fBool ? *t.fIfTrue : *t.fIfFalse); + } + case Expression::kTypeReference_Kind: + break; + default: + break; + } + ABORT("unsupported expression: %s\n", expr.description().c_str()); +} + +} // namespace + +#endif |