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.
101 // This is done simply by disabling all function calls - built-in math functions don't use
102 // the function call ops.
103 if (node->isFunctionCall())
104 {
105 onNonConstInitializerVisit(mExtNonConstGlobalInitializers);
106 }
107 return true;
108 }
109
visitBinary(Visit visit,TIntermBinary * node)110 bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
111 {
112 if (node->isAssignment())
113 {
114 onNonConstInitializerVisit(mExtNonConstGlobalInitializers);
115 }
116 return true;
117 }
118
visitUnary(Visit visit,TIntermUnary * node)119 bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
120 {
121 if (node->isAssignment())
122 {
123 onNonConstInitializerVisit(mExtNonConstGlobalInitializers);
124 }
125 return true;
126 }
127
ValidateGlobalInitializerTraverser(int shaderVersion,bool isWebGL,bool hasExtNonConstGlobalInitializers)128 ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(
129 int shaderVersion,
130 bool isWebGL,
131 bool hasExtNonConstGlobalInitializers)
132 : TIntermTraverser(true, false, false, nullptr),
133 mShaderVersion(shaderVersion),
134 mIsWebGL(isWebGL),
135 mExtNonConstGlobalInitializers(hasExtNonConstGlobalInitializers),
136 mIsValid(true),
137 mIssueWarning(false)
138 {
139 setMaxAllowedDepth(kMaxAllowedTraversalDepth);
140 }
141
142 } // namespace
143
ValidateGlobalInitializer(TIntermTyped * initializer,int shaderVersion,bool isWebGL,bool hasExtNonConstGlobalInitializers,bool * warning)144 bool ValidateGlobalInitializer(TIntermTyped *initializer,
145 int shaderVersion,
146 bool isWebGL,
147 bool hasExtNonConstGlobalInitializers,
148 bool *warning)
149 {
150 ValidateGlobalInitializerTraverser validate(shaderVersion, isWebGL,
151 hasExtNonConstGlobalInitializers);
152 initializer->traverse(&validate);
153 ASSERT(warning != nullptr);
154 *warning = validate.issueWarning();
155 return validate.isValid();
156 }
157
158 } // namespace sh
159