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