• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "compiler/translator/ValidateGlobalInitializer.h"
8 
9 #include "compiler/translator/tree_util/IntermTraverse.h"
10 
11 namespace sh
12 {
13 
14 namespace
15 {
16 
17 const int kMaxAllowedTraversalDepth = 256;
18 
19 class ValidateGlobalInitializerTraverser : public TIntermTraverser
20 {
21   public:
22     ValidateGlobalInitializerTraverser(int shaderVersion,
23                                        bool isWebGL,
24                                        bool hasExtNonConstGlobalInitializers);
25 
26     void visitSymbol(TIntermSymbol *node) override;
27     void visitConstantUnion(TIntermConstantUnion *node) override;
28     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
29     bool visitBinary(Visit visit, TIntermBinary *node) override;
30     bool visitUnary(Visit visit, TIntermUnary *node) override;
31 
isValid() const32     bool isValid() const { return mIsValid && mMaxDepth < mMaxAllowedDepth; }
issueWarning() const33     bool issueWarning() const { return mIssueWarning; }
34 
35   private:
onNonConstInitializerVisit(bool accept)36     ANGLE_INLINE void onNonConstInitializerVisit(bool accept)
37     {
38         if (accept)
39         {
40             if (!mExtNonConstGlobalInitializers)
41             {
42                 mIssueWarning = true;
43             }
44         }
45         else
46         {
47             mIsValid = false;
48         }
49     }
50 
51     int mShaderVersion;
52     bool mIsWebGL;
53     bool mExtNonConstGlobalInitializers;
54     bool mIsValid;
55     bool mIssueWarning;
56 };
57 
visitSymbol(TIntermSymbol * node)58 void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
59 {
60     // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
61     // Global initializers must be constant expressions.
62     switch (node->getType().getQualifier())
63     {
64         case EvqConst:
65             break;
66         case EvqGlobal:
67         case EvqTemporary:
68         case EvqUniform:
69             // We allow these cases to be compatible with legacy ESSL 1.00 content.
70             // Implement stricter rules for ESSL 3.00 since there's no legacy content to deal
71             // with.
72             onNonConstInitializerVisit(mExtNonConstGlobalInitializers ||
73                                        ((mShaderVersion < 300) && mIsWebGL));
74             break;
75         default:
76             mIsValid = false;
77     }
78 }
79 
visitConstantUnion(TIntermConstantUnion * node)80 void ValidateGlobalInitializerTraverser::visitConstantUnion(TIntermConstantUnion *node)
81 {
82     // Constant unions that are not constant expressions may result from folding a ternary
83     // expression.
84     switch (node->getType().getQualifier())
85     {
86         case EvqConst:
87             break;
88         case EvqTemporary:
89             onNonConstInitializerVisit(mExtNonConstGlobalInitializers ||
90                                        ((mShaderVersion < 300) && mIsWebGL));
91             break;
92         default:
93             UNREACHABLE();
94     }
95 }
96 
visitAggregate(Visit visit,TIntermAggregate * node)97 bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
98 {
99     // Disallow calls to user-defined functions and texture lookup functions in global variable
100     // initializers.  For simplicity, all non-math built-in calls are disallowed.
101     if (node->isFunctionCall() ||
102         (BuiltInGroup::IsBuiltIn(node->getOp()) && !BuiltInGroup::IsMath(node->getOp())))
103     {
104         onNonConstInitializerVisit(mExtNonConstGlobalInitializers);
105     }
106     return true;
107 }
108 
visitBinary(Visit visit,TIntermBinary * node)109 bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
110 {
111     if (node->isAssignment())
112     {
113         onNonConstInitializerVisit(mExtNonConstGlobalInitializers);
114     }
115     return true;
116 }
117 
visitUnary(Visit visit,TIntermUnary * node)118 bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
119 {
120     if (node->isAssignment())
121     {
122         onNonConstInitializerVisit(mExtNonConstGlobalInitializers);
123     }
124     return true;
125 }
126 
ValidateGlobalInitializerTraverser(int shaderVersion,bool isWebGL,bool hasExtNonConstGlobalInitializers)127 ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(
128     int shaderVersion,
129     bool isWebGL,
130     bool hasExtNonConstGlobalInitializers)
131     : TIntermTraverser(true, false, false, nullptr),
132       mShaderVersion(shaderVersion),
133       mIsWebGL(isWebGL),
134       mExtNonConstGlobalInitializers(hasExtNonConstGlobalInitializers),
135       mIsValid(true),
136       mIssueWarning(false)
137 {
138     setMaxAllowedDepth(kMaxAllowedTraversalDepth);
139 }
140 
141 }  // namespace
142 
ValidateGlobalInitializer(TIntermTyped * initializer,int shaderVersion,bool isWebGL,bool hasExtNonConstGlobalInitializers,bool * warning)143 bool ValidateGlobalInitializer(TIntermTyped *initializer,
144                                int shaderVersion,
145                                bool isWebGL,
146                                bool hasExtNonConstGlobalInitializers,
147                                bool *warning)
148 {
149     ValidateGlobalInitializerTraverser validate(shaderVersion, isWebGL,
150                                                 hasExtNonConstGlobalInitializers);
151     initializer->traverse(&validate);
152     ASSERT(warning != nullptr);
153     *warning = validate.issueWarning();
154     return validate.isValid();
155 }
156 
157 }  // namespace sh
158