xref: /aosp_15_r20/external/skia/src/sksl/analysis/SkSLIsDynamicallyUniformExpression.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/SkTypes.h"
9 #include "src/sksl/SkSLAnalysis.h"
10 #include "src/sksl/analysis/SkSLProgramVisitor.h"
11 #include "src/sksl/ir/SkSLExpression.h"
12 #include "src/sksl/ir/SkSLFunctionCall.h"
13 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
14 #include "src/sksl/ir/SkSLIRNode.h"
15 #include "src/sksl/ir/SkSLModifierFlags.h"
16 #include "src/sksl/ir/SkSLVariable.h"
17 #include "src/sksl/ir/SkSLVariableReference.h"
18 
19 namespace SkSL {
20 
IsDynamicallyUniformExpression(const Expression & expr)21 bool Analysis::IsDynamicallyUniformExpression(const Expression& expr) {
22     class IsDynamicallyUniformExpressionVisitor : public ProgramVisitor {
23     public:
24         bool visitExpression(const Expression& expr) override {
25             switch (expr.kind()) {
26                 case Expression::Kind::kBinary:
27                 case Expression::Kind::kConstructorArray:
28                 case Expression::Kind::kConstructorArrayCast:
29                 case Expression::Kind::kConstructorCompound:
30                 case Expression::Kind::kConstructorCompoundCast:
31                 case Expression::Kind::kConstructorDiagonalMatrix:
32                 case Expression::Kind::kConstructorMatrixResize:
33                 case Expression::Kind::kConstructorScalarCast:
34                 case Expression::Kind::kConstructorSplat:
35                 case Expression::Kind::kConstructorStruct:
36                 case Expression::Kind::kFieldAccess:
37                 case Expression::Kind::kIndex:
38                 case Expression::Kind::kPostfix:
39                 case Expression::Kind::kPrefix:
40                 case Expression::Kind::kSwizzle:
41                 case Expression::Kind::kTernary:
42                     // These expressions might be dynamically uniform, if they are composed entirely
43                     // of constants and uniforms.
44                     break;
45 
46                 case Expression::Kind::kVariableReference: {
47                     // Verify that variable references are const or uniform.
48                     const Variable* var = expr.as<VariableReference>().variable();
49                     if (var && (var->modifierFlags().isConst() ||
50                                 var->modifierFlags().isUniform())) {
51                         break;
52                     }
53                     fIsDynamicallyUniform = false;
54                     return true;
55                 }
56                 case Expression::Kind::kFunctionCall: {
57                     // Verify that function calls are pure.
58                     const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
59                     if (decl.modifierFlags().isPure()) {
60                         break;
61                     }
62                     fIsDynamicallyUniform = false;
63                     return true;
64                 }
65                 case Expression::Kind::kLiteral:
66                     // Literals are compile-time constants.
67                     return false;
68 
69                 default:
70                     // This expression isn't dynamically uniform.
71                     fIsDynamicallyUniform = false;
72                     return true;
73             }
74             return INHERITED::visitExpression(expr);
75         }
76 
77         bool fIsDynamicallyUniform = true;
78         using INHERITED = ProgramVisitor;
79     };
80 
81     IsDynamicallyUniformExpressionVisitor visitor;
82     visitor.visitExpression(expr);
83     return visitor.fIsDynamicallyUniform;
84 }
85 
86 }  // namespace SkSL
87