/*
|
* 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"
|
|
namespace SkSL {
|
|
void Interpreter::run() {
|
for (const auto& e : *fProgram) {
|
if (ProgramElement::kFunction_Kind == e.fKind) {
|
const FunctionDefinition& f = (const FunctionDefinition&) e;
|
if ("appendStages" == f.fDeclaration.fName) {
|
this->run(f);
|
return;
|
}
|
}
|
}
|
SkASSERT(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;
|
}
|
SkASSERT(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:
|
SkASSERT(index == 0);
|
abort();
|
case Statement::kContinue_Kind:
|
SkASSERT(index == 0);
|
abort();
|
case Statement::kDiscard_Kind:
|
SkASSERT(index == 0);
|
abort();
|
case Statement::kDo_Kind:
|
abort();
|
case Statement::kExpression_Kind:
|
SkASSERT(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:
|
SkASSERT(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:
|
SkASSERT(index == 0);
|
break;
|
case Statement::kReturn_Kind:
|
SkASSERT(index == 0);
|
abort();
|
case Statement::kSwitch_Kind:
|
abort();
|
case Statement::kVarDeclarations_Kind:
|
SkASSERT(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:
|
SkASSERT(fVars.size());
|
SkASSERT(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 SkRasterPipeline_CallbackCtx {
|
Interpreter* fInterpreter;
|
const FunctionDefinition* fFunction;
|
};
|
|
static void do_callback(SkRasterPipeline_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: {
|
SkASSERT(a.fArguments.size() == 1);
|
StackIndex transpose = evaluate(*a.fArguments[0]).fInt;
|
fPipeline.append(SkRasterPipeline::matrix_4x5, &fStack[transpose]);
|
break;
|
}
|
case SkRasterPipeline::callback: {
|
SkASSERT(a.fArguments.size() == 1);
|
CallbackCtx* ctx = new CallbackCtx();
|
ctx->fInterpreter = this;
|
ctx->fn = do_callback;
|
for (const auto& e : *fProgram) {
|
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 {
|
SkASSERT(Token::MINUSMINUS == p.fOperator);
|
--fStack[lvalue].fFloat;
|
}
|
break;
|
case kInt_TypeKind:
|
if (Token::PLUSPLUS == p.fOperator) {
|
++fStack[lvalue].fInt;
|
} else {
|
SkASSERT(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:
|
SkASSERT(fVars.size());
|
SkASSERT(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
|