1 /* 2 * Copyright 2023 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "include/core/SkSpan.h" 9 #include "include/core/SkTypes.h" 10 #include "include/private/base/SkTArray.h" 11 #include "src/sksl/SkSLAnalysis.h" 12 #include "src/sksl/analysis/SkSLProgramUsage.h" 13 #include "src/sksl/analysis/SkSLProgramVisitor.h" 14 #include "src/sksl/ir/SkSLConstructor.h" 15 #include "src/sksl/ir/SkSLConstructorCompound.h" 16 #include "src/sksl/ir/SkSLConstructorCompoundCast.h" 17 #include "src/sksl/ir/SkSLConstructorSplat.h" 18 #include "src/sksl/ir/SkSLExpression.h" 19 #include "src/sksl/ir/SkSLFunctionDeclaration.h" 20 #include "src/sksl/ir/SkSLFunctionDefinition.h" 21 #include "src/sksl/ir/SkSLProgramElement.h" 22 #include "src/sksl/ir/SkSLReturnStatement.h" 23 #include "src/sksl/ir/SkSLStatement.h" 24 #include "src/sksl/ir/SkSLSwizzle.h" 25 #include "src/sksl/ir/SkSLTernaryExpression.h" 26 #include "src/sksl/ir/SkSLType.h" 27 #include "src/sksl/ir/SkSLVariable.h" 28 #include "src/sksl/ir/SkSLVariableReference.h" 29 30 #include <memory> 31 32 using namespace skia_private; 33 34 namespace SkSL { 35 namespace { 36 37 class ReturnsInputAlphaVisitor : public ProgramVisitor { 38 public: ReturnsInputAlphaVisitor(const ProgramUsage & u)39 ReturnsInputAlphaVisitor(const ProgramUsage& u) : fUsage(u) {} 40 visitProgramElement(const ProgramElement & pe)41 bool visitProgramElement(const ProgramElement& pe) override { 42 const FunctionDeclaration& decl = pe.as<FunctionDefinition>().declaration(); 43 SkSpan<Variable* const> parameters = decl.parameters(); 44 45 // We expect a color filter to have a single half4 input. 46 if (parameters.size() != 1 || 47 parameters[0]->type().columns() != 4 || 48 !parameters[0]->type().componentType().isFloat()) { 49 // This doesn't look like a color filter. 50 return true; 51 } 52 fInputVar = parameters[0]; 53 54 // If the input variable has been written-to, then returning `input.a` isn't sufficient to 55 // guarantee that alpha is preserved. 56 ProgramUsage::VariableCounts counts = fUsage.get(*fInputVar); 57 if (counts.fWrite != 0) { 58 return true; 59 } 60 61 return INHERITED::visitProgramElement(pe); 62 } 63 isInputVar(const Expression & expr)64 bool isInputVar(const Expression& expr) { 65 return expr.is<VariableReference>() && expr.as<VariableReference>().variable() == fInputVar; 66 } 67 isInputSwizzleEndingWithAlpha(const Expression & expr)68 bool isInputSwizzleEndingWithAlpha(const Expression& expr) { 69 if (!expr.is<Swizzle>()) { 70 return false; 71 } 72 const Swizzle& swizzle = expr.as<Swizzle>(); 73 return this->isInputVar(*swizzle.base()) && swizzle.components().back() == 3; 74 } 75 returnsInputAlpha(const Expression & expr)76 bool returnsInputAlpha(const Expression& expr) { 77 if (this->isInputVar(expr)) { 78 // This expression returns the input value as-is. 79 return true; 80 } 81 if (expr.is<Swizzle>()) { 82 // It's a swizzle: check for `input.___a`. 83 return this->isInputSwizzleEndingWithAlpha(expr); 84 } 85 if (expr.is<ConstructorSplat>() || expr.is<ConstructorCompound>()) { 86 // This is a splat or compound constructor; check for `input.a` as its final component. 87 const AnyConstructor& ctor = expr.asAnyConstructor(); 88 return this->returnsInputAlpha(*ctor.argumentSpan().back()); 89 } 90 if (expr.is<ConstructorCompoundCast>()) { 91 // Ignore typecasts between float and half. 92 const Expression& arg = *expr.as<ConstructorCompoundCast>().argument(); 93 return arg.type().componentType().isFloat() && this->returnsInputAlpha(arg); 94 } 95 if (expr.is<TernaryExpression>()) { 96 // Both sides of the ternary must preserve input alpha. 97 const TernaryExpression& ternary = expr.as<TernaryExpression>(); 98 return this->returnsInputAlpha(*ternary.ifTrue()) && 99 this->returnsInputAlpha(*ternary.ifFalse()); 100 } 101 // We weren't able to pattern-match here. 102 return false; 103 } 104 visitStatement(const Statement & s)105 bool visitStatement(const Statement& s) override { 106 if (s.is<ReturnStatement>()) { 107 return !this->returnsInputAlpha(*s.as<ReturnStatement>().expression()); 108 } 109 return INHERITED::visitStatement(s); 110 } 111 visitExpression(const Expression & e)112 bool visitExpression(const Expression& e) override { 113 // No need to recurse into expressions; these can never contain return statements. 114 return false; 115 } 116 117 private: 118 const ProgramUsage& fUsage; 119 const Variable* fInputVar = nullptr; 120 121 using INHERITED = ProgramVisitor; 122 }; 123 124 } // namespace 125 ReturnsInputAlpha(const FunctionDefinition & function,const ProgramUsage & usage)126bool Analysis::ReturnsInputAlpha(const FunctionDefinition& function, const ProgramUsage& usage) { 127 ReturnsInputAlphaVisitor visitor{usage}; 128 return !visitor.visitProgramElement(function); 129 } 130 131 } // namespace SkSL 132