blob: a89738681104bdb4baf455ae5956e03c6f6603fb [file] [log] [blame]
/*
* Copyright 2019 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/sksl/SkSLSectionAndParameterHelper.h"
#include "src/sksl/ir/SkSLBinaryExpression.h"
#include "src/sksl/ir/SkSLConstructor.h"
#include "src/sksl/ir/SkSLDoStatement.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/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/SkSLWhileStatement.h"
namespace SkSL {
SectionAndParameterHelper::SectionAndParameterHelper(const Program* program, ErrorReporter& errors)
: fProgram(*program) {
for (const auto& p : fProgram) {
switch (p.fKind) {
case ProgramElement::kVar_Kind: {
const VarDeclarations& decls = (const VarDeclarations&) p;
for (const auto& raw : decls.fVars) {
const VarDeclaration& decl = (VarDeclaration&) *raw;
if (IsParameter(*decl.fVar)) {
fParameters.push_back(decl.fVar);
}
}
break;
}
case ProgramElement::kSection_Kind: {
const Section& s = (const Section&) p;
if (IsSupportedSection(s.fName.c_str())) {
if (SectionRequiresArgument(s.fName.c_str()) && !s.fArgument.size()) {
errors.error(s.fOffset,
("section '@" + s.fName +
"' requires one parameter").c_str());
}
if (!SectionAcceptsArgument(s.fName.c_str()) && s.fArgument.size()) {
errors.error(s.fOffset,
("section '@" + s.fName + "' has no parameters").c_str());
}
} else {
errors.error(s.fOffset,
("unsupported section '@" + s.fName + "'").c_str());
}
if (!SectionPermitsDuplicates(s.fName.c_str()) &&
fSections.find(s.fName) != fSections.end()) {
errors.error(s.fOffset,
("duplicate section '@" + s.fName + "'").c_str());
}
fSections[s.fName].push_back(&s);
break;
}
default:
break;
}
}
}
bool SectionAndParameterHelper::hasCoordOverrides(const Variable& fp) {
for (const auto& pe : fProgram) {
if (this->hasCoordOverrides(pe, fp)) {
return true;
}
}
return false;
}
bool SectionAndParameterHelper::hasCoordOverrides(const ProgramElement& pe, const Variable& fp) {
if (pe.fKind == ProgramElement::kFunction_Kind) {
return this->hasCoordOverrides(*((const FunctionDefinition&) pe).fBody, fp);
}
return false;
}
bool SectionAndParameterHelper::hasCoordOverrides(const Expression& e, const Variable& fp) {
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->fFloat2_Type &&
fc.fArguments[0]->fKind == Expression::kVariableReference_Kind &&
&((VariableReference&) *fc.fArguments[0]).fVariable == &fp) {
return true;
}
for (const auto& e : fc.fArguments) {
if (this->hasCoordOverrides(*e, fp)) {
return true;
}
}
return false;
}
case Expression::kConstructor_Kind: {
const Constructor& c = (const Constructor&) e;
for (const auto& e : c.fArguments) {
if (this->hasCoordOverrides(*e, fp)) {
return true;
}
}
return false;
}
case Expression::kFieldAccess_Kind: {
return this->hasCoordOverrides(*((const FieldAccess&) e).fBase, fp);
}
case Expression::kSwizzle_Kind:
return this->hasCoordOverrides(*((const Swizzle&) e).fBase, fp);
case Expression::kBinary_Kind: {
const BinaryExpression& b = (const BinaryExpression&) e;
return this->hasCoordOverrides(*b.fLeft, fp) ||
this->hasCoordOverrides(*b.fRight, fp);
}
case Expression::kIndex_Kind: {
const IndexExpression& idx = (const IndexExpression&) e;
return this->hasCoordOverrides(*idx.fBase, fp) ||
this->hasCoordOverrides(*idx.fIndex, fp);
}
case Expression::kPrefix_Kind:
return this->hasCoordOverrides(*((const PrefixExpression&) e).fOperand, fp);
case Expression::kPostfix_Kind:
return this->hasCoordOverrides(*((const PostfixExpression&) e).fOperand, fp);
case Expression::kTernary_Kind: {
const TernaryExpression& t = (const TernaryExpression&) e;
return this->hasCoordOverrides(*t.fTest, fp) ||
this->hasCoordOverrides(*t.fIfTrue, fp) ||
this->hasCoordOverrides(*t.fIfFalse, fp);
}
case Expression::kVariableReference_Kind:
return false;
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 false;
}
SkASSERT(false);
return false;
}
bool SectionAndParameterHelper::hasCoordOverrides(const Statement& s, const Variable& fp) {
switch (s.fKind) {
case Statement::kBlock_Kind: {
for (const auto& child : ((const Block&) s).fStatements) {
if (this->hasCoordOverrides(*child, fp)) {
return true;
}
}
return false;
}
case Statement::kVarDeclaration_Kind: {
const VarDeclaration& var = (const VarDeclaration&) s;
if (var.fValue) {
return hasCoordOverrides(*var.fValue, fp);
}
return false;
}
case Statement::kVarDeclarations_Kind: {
const VarDeclarations& decls = *((const VarDeclarationsStatement&) s).fDeclaration;
for (const auto& stmt : decls.fVars) {
if (this->hasCoordOverrides(*stmt, fp)) {
return true;
}
}
return false;
}
case Statement::kExpression_Kind:
return this->hasCoordOverrides(*((const ExpressionStatement&) s).fExpression, fp);
case Statement::kReturn_Kind: {
const ReturnStatement& r = (const ReturnStatement&) s;
if (r.fExpression) {
return this->hasCoordOverrides(*r.fExpression, fp);
}
return false;
}
case Statement::kIf_Kind: {
const IfStatement& i = (const IfStatement&) s;
return this->hasCoordOverrides(*i.fTest, fp) ||
this->hasCoordOverrides(*i.fIfTrue, fp) ||
(i.fIfFalse && this->hasCoordOverrides(*i.fIfFalse, fp));
}
case Statement::kFor_Kind: {
const ForStatement& f = (const ForStatement&) s;
return this->hasCoordOverrides(*f.fInitializer, fp) ||
this->hasCoordOverrides(*f.fTest, fp) ||
this->hasCoordOverrides(*f.fNext, fp) ||
this->hasCoordOverrides(*f.fStatement, fp);
}
case Statement::kWhile_Kind: {
const WhileStatement& w = (const WhileStatement&) s;
return this->hasCoordOverrides(*w.fTest, fp) ||
this->hasCoordOverrides(*w.fStatement, fp);
}
case Statement::kDo_Kind: {
const DoStatement& d = (const DoStatement&) s;
return this->hasCoordOverrides(*d.fTest, fp) ||
this->hasCoordOverrides(*d.fStatement, fp);
}
case Statement::kSwitch_Kind: {
const SwitchStatement& sw = (const SwitchStatement&) s;
for (const auto& c : sw.fCases) {
for (const auto& st : c->fStatements) {
if (this->hasCoordOverrides(*st, fp)) {
return true;
}
}
}
return this->hasCoordOverrides(*sw.fValue, fp);
}
case Statement::kBreak_Kind:
case Statement::kContinue_Kind:
case Statement::kDiscard_Kind:
case Statement::kGroup_Kind:
case Statement::kNop_Kind:
return false;
}
SkASSERT(false);
return false;
}
SampleMatrix SectionAndParameterHelper::getMatrix(const Variable& fp) {
SampleMatrix result;
for (const auto& pe : fProgram) {
result.merge(this->getMatrix(pe, fp));
}
return result;
}
SampleMatrix SectionAndParameterHelper::getMatrix(const ProgramElement& pe, const Variable& fp) {
if (pe.fKind == ProgramElement::kFunction_Kind) {
return this->getMatrix(*((const FunctionDefinition&) pe).fBody, fp);
}
return SampleMatrix();
}
SampleMatrix SectionAndParameterHelper::getMatrix(const Expression& e, const Variable& fp) {
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 == &fp) {
if (fc.fArguments.back()->isConstantOrUniform()) {
return SampleMatrix(SampleMatrix::Kind::kConstantOrUniform, nullptr,
fc.fArguments.back()->description());
} else {
return SampleMatrix(SampleMatrix::Kind::kVariable);
}
}
SampleMatrix result;
for (const auto& e : fc.fArguments) {
result.merge(this->getMatrix(*e, fp));
}
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, fp));
}
return result;
}
case Expression::kFieldAccess_Kind: {
return this->getMatrix(*((const FieldAccess&) e).fBase, fp);
}
case Expression::kSwizzle_Kind:
return this->getMatrix(*((const Swizzle&) e).fBase, fp);
case Expression::kBinary_Kind: {
const BinaryExpression& b = (const BinaryExpression&) e;
return this->getMatrix(*b.fLeft, fp).merge(this->getMatrix(*b.fRight, fp));
}
case Expression::kIndex_Kind: {
const IndexExpression& idx = (const IndexExpression&) e;
return this->getMatrix(*idx.fBase, fp).merge(this->getMatrix(*idx.fIndex, fp));
}
case Expression::kPrefix_Kind:
return this->getMatrix(*((const PrefixExpression&) e).fOperand, fp);
case Expression::kPostfix_Kind:
return this->getMatrix(*((const PostfixExpression&) e).fOperand, fp);
case Expression::kTernary_Kind: {
const TernaryExpression& t = (const TernaryExpression&) e;
return this->getMatrix(*t.fTest, fp).merge(this->getMatrix(*t.fIfTrue, fp)).merge(
this->getMatrix(*t.fIfFalse, fp));
}
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 SectionAndParameterHelper::getMatrix(const Statement& s, const Variable& fp) {
switch (s.fKind) {
case Statement::kBlock_Kind: {
SampleMatrix result;
for (const auto& child : ((const Block&) s).fStatements) {
result.merge(this->getMatrix(*child, fp));
}
return result;
}
case Statement::kVarDeclaration_Kind: {
const VarDeclaration& var = (const VarDeclaration&) s;
if (var.fValue) {
return this->getMatrix(*var.fValue, fp);
}
return SampleMatrix();
}
case Statement::kVarDeclarations_Kind: {
const VarDeclarations& decls = *((const VarDeclarationsStatement&) s).fDeclaration;
SampleMatrix result;
for (const auto& stmt : decls.fVars) {
result.merge(this->getMatrix(*stmt, fp));
}
return result;
}
case Statement::kExpression_Kind:
return this->getMatrix(*((const ExpressionStatement&) s).fExpression, fp);
case Statement::kReturn_Kind: {
const ReturnStatement& r = (const ReturnStatement&) s;
if (r.fExpression) {
return this->getMatrix(*r.fExpression, fp);
}
return SampleMatrix();
}
case Statement::kIf_Kind: {
const IfStatement& i = (const IfStatement&) s;
return this->getMatrix(*i.fTest, fp).merge(this->getMatrix(*i.fIfTrue, fp)).merge(
(i.fIfFalse ? this->getMatrix(*i.fIfFalse, fp) : SampleMatrix()));
}
case Statement::kFor_Kind: {
const ForStatement& f = (const ForStatement&) s;
return this->getMatrix(*f.fInitializer, fp).merge(
this->getMatrix(*f.fTest, fp).merge(
this->getMatrix(*f.fNext, fp).merge(
this->getMatrix(*f.fStatement, fp))));
}
case Statement::kWhile_Kind: {
const WhileStatement& w = (const WhileStatement&) s;
return this->getMatrix(*w.fTest, fp).merge(this->getMatrix(*w.fStatement, fp));
}
case Statement::kDo_Kind: {
const DoStatement& d = (const DoStatement&) s;
return this->getMatrix(*d.fTest, fp).merge(this->getMatrix(*d.fStatement, fp));
}
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, fp));
}
}
return result.merge(this->getMatrix(*sw.fValue, fp));
}
case Statement::kBreak_Kind:
case Statement::kContinue_Kind:
case Statement::kDiscard_Kind:
case Statement::kGroup_Kind:
case Statement::kNop_Kind:
return SampleMatrix();
}
SkASSERT(false);
return SampleMatrix();
}
}