blob: a7fed99306c376b71c8be831f337104fff40519e [file] [log] [blame]
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/private/SkSLSampleMatrix.h"
#include "src/sksl/ir/SkSLBinaryExpression.h"
#include "src/sksl/ir/SkSLConstructor.h"
#include "src/sksl/ir/SkSLDoStatement.h"
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLExpressionStatement.h"
#include "src/sksl/ir/SkSLFieldAccess.h"
#include "src/sksl/ir/SkSLForStatement.h"
#include "src/sksl/ir/SkSLFunctionCall.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/SkSLReturnStatement.h"
#include "src/sksl/ir/SkSLSwitchStatement.h"
#include "src/sksl/ir/SkSLSwizzle.h"
#include "src/sksl/ir/SkSLTernaryExpression.h"
#include "src/sksl/ir/SkSLVarDeclarationsStatement.h"
#include "src/sksl/ir/SkSLVariable.h"
#include "src/sksl/ir/SkSLWhileStatement.h"
namespace SkSL {
SampleMatrix SampleMatrix::merge(const SampleMatrix& other) {
if (fKind == Kind::kVariable || other.fKind == Kind::kVariable) {
*this = SampleMatrix::MakeVariable(this->fHasPerspective || other.fHasPerspective);
return *this;
}
if (other.fKind == Kind::kConstantOrUniform) {
if (fKind == other.fKind) {
if (fExpression == other.fExpression) {
return *this;
}
*this = SampleMatrix::MakeVariable(this->fHasPerspective || other.fHasPerspective);
return *this;
}
SkASSERT(fKind == Kind::kNone);
*this = other;
return *this;
}
return *this;
}
struct SampleMatrixExtractor {
SampleMatrixExtractor(const Program& program, const Variable& fp)
: fProgram(program), fFP(fp) {}
SampleMatrix getMatrix(const Expression&) const;
SampleMatrix getMatrix(const Statement&) const;
SampleMatrix getMatrix(const Expression* e) const {
return e ? this->getMatrix(*e) : SampleMatrix();
}
SampleMatrix getMatrix(const Statement* s) const {
return s ? this->getMatrix(*s) : SampleMatrix();
}
SampleMatrix getMatrix(const ProgramElement& pe) const {
if (pe.fKind == ProgramElement::kFunction_Kind) {
return this->getMatrix(*((const FunctionDefinition&) pe).fBody);
}
return SampleMatrix();
}
const Program& fProgram;
const Variable& fFP;
};
SampleMatrix SampleMatrix::Make(const Program& program, const Variable& fp) {
SampleMatrix result;
SampleMatrixExtractor extractor(program, fp);
for (const auto& pe : program) {
result.merge(extractor.getMatrix(pe));
}
return result;
}
SampleMatrix SampleMatrixExtractor::getMatrix(const Expression& e) const {
switch (e.fKind) {
case Expression::kFunctionCall_Kind: {
const FunctionCall& fc = (const FunctionCall&) e;
const FunctionDeclaration& f = fc.fFunction;
if (f.fBuiltin && f.fName == "sample" && fc.fArguments.size() >= 2 &&
fc.fArguments.back()->fType == *fProgram.fContext->fFloat3x3_Type &&
fc.fArguments[0]->fKind == Expression::kVariableReference_Kind &&
&((VariableReference&) *fc.fArguments[0]).fVariable == &fFP) {
if (fc.fArguments.back()->isConstantOrUniform()) {
if (fc.fArguments.back()->fKind == Expression::Kind::kVariableReference_Kind ||
fc.fArguments.back()->fKind == Expression::Kind::kConstructor_Kind) {
// FIXME if this is a constant, we should parse the float3x3 constructor and
// determine if the resulting matrix introduces perspective.
return SampleMatrix::MakeConstUniform(fc.fArguments.back()->description());
} else {
// FIXME this is really to workaround a restriction of the downstream code
// that relies on the SampleMatrix's fExpression to identify uniform names.
// Once they are tracked separately, any constant/uniform expression can
// work, but right now this avoids issues from '0.5 * matrix' that is both
// a constant AND a uniform.
return SampleMatrix::MakeVariable();
}
} else {
return SampleMatrix::MakeVariable();
}
}
SampleMatrix result;
for (const auto& e : fc.fArguments) {
result.merge(this->getMatrix(*e));
}
return result;
}
case Expression::kConstructor_Kind: {
SampleMatrix result;
const Constructor& c = (const Constructor&) e;
for (const auto& e : c.fArguments) {
result.merge(this->getMatrix(*e));
}
return result;
}
case Expression::kFieldAccess_Kind:
return this->getMatrix(*((const FieldAccess&) e).fBase);
case Expression::kSwizzle_Kind:
return this->getMatrix(*((const Swizzle&) e).fBase);
case Expression::kBinary_Kind: {
const BinaryExpression& b = (const BinaryExpression&) e;
return this->getMatrix(*b.fLeft).merge(
this->getMatrix(*b.fRight));
}
case Expression::kIndex_Kind: {
const IndexExpression& idx = (const IndexExpression&) e;
return this->getMatrix(*idx.fBase).merge(
this->getMatrix(*idx.fIndex));
}
case Expression::kPrefix_Kind:
return this->getMatrix(*((const PrefixExpression&) e).fOperand);
case Expression::kPostfix_Kind:
return this->getMatrix(*((const PostfixExpression&) e).fOperand);
case Expression::kTernary_Kind: {
const TernaryExpression& t = (const TernaryExpression&) e;
return this->getMatrix(*t.fTest).merge(
this->getMatrix(*t.fIfTrue)).merge(
this->getMatrix(*t.fIfFalse));
}
case Expression::kVariableReference_Kind:
return SampleMatrix();
case Expression::kBoolLiteral_Kind:
case Expression::kDefined_Kind:
case Expression::kExternalFunctionCall_Kind:
case Expression::kExternalValue_Kind:
case Expression::kFloatLiteral_Kind:
case Expression::kFunctionReference_Kind:
case Expression::kIntLiteral_Kind:
case Expression::kNullLiteral_Kind:
case Expression::kSetting_Kind:
case Expression::kTypeReference_Kind:
return SampleMatrix();
}
SkASSERT(false);
return SampleMatrix();
}
SampleMatrix SampleMatrixExtractor::getMatrix(const Statement& s) const {
switch (s.fKind) {
case Statement::kBlock_Kind: {
SampleMatrix result;
for (const auto& child : ((const Block&) s).fStatements) {
result.merge(this->getMatrix(*child));
}
return result;
}
case Statement::kVarDeclaration_Kind:
return this->getMatrix(((const VarDeclaration&) s).fValue.get());
case Statement::kVarDeclarations_Kind: {
const VarDeclarations& decls = *((const VarDeclarationsStatement&) s).fDeclaration;
SampleMatrix result;
for (const auto& stmt : decls.fVars) {
result.merge(this->getMatrix(*stmt));
}
return result;
}
case Statement::kExpression_Kind:
return this->getMatrix(*((const ExpressionStatement&) s).fExpression);
case Statement::kReturn_Kind:
return this->getMatrix(((const ReturnStatement&) s).fExpression.get());
case Statement::kIf_Kind: {
const IfStatement& i = (const IfStatement&) s;
return this->getMatrix(*i.fTest).merge(
this->getMatrix(*i.fIfTrue)).merge(
this->getMatrix(i.fIfFalse.get()));
}
case Statement::kFor_Kind: {
const ForStatement& f = (const ForStatement&) s;
return this->getMatrix(f.fInitializer.get()).merge(
this->getMatrix(f.fTest.get()).merge(
this->getMatrix(f.fNext.get()).merge(
this->getMatrix(*f.fStatement))));
}
case Statement::kWhile_Kind: {
const WhileStatement& w = (const WhileStatement&) s;
return this->getMatrix(*w.fTest).merge(
this->getMatrix(*w.fStatement));
}
case Statement::kDo_Kind: {
const DoStatement& d = (const DoStatement&) s;
return this->getMatrix(*d.fTest).merge(
this->getMatrix(*d.fStatement));
}
case Statement::kSwitch_Kind: {
SampleMatrix result;
const SwitchStatement& sw = (const SwitchStatement&) s;
for (const auto& c : sw.fCases) {
for (const auto& st : c->fStatements) {
result.merge(this->getMatrix(*st));
}
}
return result.merge(this->getMatrix(*sw.fValue));
}
case Statement::kBreak_Kind:
case Statement::kContinue_Kind:
case Statement::kDiscard_Kind:
case Statement::kNop_Kind:
return SampleMatrix();
}
SkASSERT(false);
return SampleMatrix();
}
} // namespace