aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/sksl/SkSLInterpreter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sksl/SkSLInterpreter.cpp')
-rw-r--r--src/sksl/SkSLInterpreter.cpp473
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