blob: 2a6d9773650532263776863d22e10747a512bc2b [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkSpan.h"
#include "include/core/SkTypes.h"
#include "include/private/SkSLDefines.h"
#include "include/private/SkSLProgramElement.h"
#include "include/private/SkSLStatement.h"
#include "src/sksl/SkSLAnalysis.h"
#include "src/sksl/analysis/SkSLProgramVisitor.h"
#include "src/sksl/ir/SkSLConstructor.h"
#include "src/sksl/ir/SkSLConstructorCompound.h"
#include "src/sksl/ir/SkSLConstructorCompoundCast.h"
#include "src/sksl/ir/SkSLConstructorSplat.h"
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
#include "src/sksl/ir/SkSLFunctionDefinition.h"
#include "src/sksl/ir/SkSLReturnStatement.h"
#include "src/sksl/ir/SkSLSwizzle.h"
#include "src/sksl/ir/SkSLTernaryExpression.h"
#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLVariable.h"
#include "src/sksl/ir/SkSLVariableReference.h"
#include <memory>
#include <vector>
namespace SkSL {
namespace {
class ReturnsInputAlphaVisitor : public ProgramVisitor {
public:
ReturnsInputAlphaVisitor() = default;
bool visitProgramElement(const ProgramElement& pe) override {
const FunctionDeclaration& decl = pe.as<FunctionDefinition>().declaration();
const std::vector<Variable*>& parameters = decl.parameters();
// We expect a color filter to have a single half4 input.
if (parameters.size() != 1 ||
parameters[0]->type().columns() != 4 ||
!parameters[0]->type().componentType().isFloat()) {
// This doesn't look like a color filter.
return true;
}
fInputVar = parameters[0];
return INHERITED::visitProgramElement(pe);
}
bool isInputVar(const Expression& expr) {
return expr.is<VariableReference>() && expr.as<VariableReference>().variable() == fInputVar;
}
bool isInputSwizzleEndingWithAlpha(const Expression& expr) {
if (!expr.is<Swizzle>()) {
return false;
}
const Swizzle& swizzle = expr.as<Swizzle>();
return this->isInputVar(*swizzle.base()) && swizzle.components().back() == 3;
}
bool returnsInputAlpha(const Expression& expr) {
if (this->isInputVar(expr)) {
// This expression returns the input value as-is.
return true;
}
if (expr.is<Swizzle>()) {
// It's a swizzle: check for `input.___a`.
return this->isInputSwizzleEndingWithAlpha(expr);
}
if (expr.is<ConstructorSplat>() || expr.is<ConstructorCompound>()) {
// This is a splat or compound constructor; check for `input.a` as its final component.
const AnyConstructor& ctor = expr.asAnyConstructor();
return this->returnsInputAlpha(*ctor.argumentSpan().back());
}
if (expr.is<ConstructorCompoundCast>()) {
// Ignore typecasts between float and half.
const Expression& arg = *expr.as<ConstructorCompoundCast>().argument();
return arg.type().componentType().isFloat() && this->returnsInputAlpha(arg);
}
if (expr.is<TernaryExpression>()) {
// Both sides of the ternary must preserve input alpha.
const TernaryExpression& ternary = expr.as<TernaryExpression>();
return this->returnsInputAlpha(*ternary.ifTrue()) &&
this->returnsInputAlpha(*ternary.ifFalse());
}
// We weren't able to pattern-match here.
return false;
}
bool visitStatement(const Statement& s) override {
if (s.is<ReturnStatement>()) {
return !this->returnsInputAlpha(*s.as<ReturnStatement>().expression());
}
return INHERITED::visitStatement(s);
}
bool visitExpression(const Expression& e) override {
// No need to recurse into expressions; these can never contain return statements.
return false;
}
private:
const Variable* fInputVar;
using INHERITED = ProgramVisitor;
};
} // namespace
bool Analysis::ReturnsInputAlpha(const FunctionDefinition& function) {
ReturnsInputAlphaVisitor visitor;
return !visitor.visitProgramElement(function);
}
} // namespace SkSL