Line data Source code
1 : //
2 : // Copyright (c) 2002-2015 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/ParseContext.h"
10 :
11 : namespace sh
12 : {
13 :
14 : namespace
15 : {
16 :
17 0 : class ValidateGlobalInitializerTraverser : public TIntermTraverser
18 : {
19 : public:
20 : ValidateGlobalInitializerTraverser(const TParseContext *context);
21 :
22 : void visitSymbol(TIntermSymbol *node) override;
23 : bool visitAggregate(Visit visit, TIntermAggregate *node) override;
24 : bool visitBinary(Visit visit, TIntermBinary *node) override;
25 : bool visitUnary(Visit visit, TIntermUnary *node) override;
26 :
27 0 : bool isValid() const { return mIsValid; }
28 0 : bool issueWarning() const { return mIssueWarning; }
29 :
30 : private:
31 : const TParseContext *mContext;
32 : bool mIsValid;
33 : bool mIssueWarning;
34 : };
35 :
36 0 : void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
37 : {
38 0 : const TSymbol *sym = mContext->symbolTable.find(node->getSymbol(), mContext->getShaderVersion());
39 0 : if (sym->isVariable())
40 : {
41 : // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
42 : // Global initializers must be constant expressions.
43 0 : const TVariable *var = static_cast<const TVariable *>(sym);
44 0 : switch (var->getType().getQualifier())
45 : {
46 : case EvqConst:
47 0 : break;
48 : case EvqGlobal:
49 : case EvqTemporary:
50 : case EvqUniform:
51 : // We allow these cases to be compatible with legacy ESSL 1.00 content.
52 : // Implement stricter rules for ESSL 3.00 since there's no legacy content to deal with.
53 0 : if (mContext->getShaderVersion() >= 300)
54 : {
55 0 : mIsValid = false;
56 : }
57 : else
58 : {
59 0 : mIssueWarning = true;
60 : }
61 0 : break;
62 : default:
63 0 : mIsValid = false;
64 : }
65 : }
66 0 : }
67 :
68 0 : bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
69 : {
70 : // Disallow calls to user-defined functions and texture lookup functions in global variable initializers.
71 : // This is done simply by disabling all function calls - built-in math functions don't use EOpFunctionCall.
72 0 : if (node->getOp() == EOpFunctionCall)
73 : {
74 0 : mIsValid = false;
75 : }
76 0 : return true;
77 : }
78 :
79 0 : bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
80 : {
81 0 : if (node->isAssignment())
82 : {
83 0 : mIsValid = false;
84 : }
85 0 : return true;
86 : }
87 :
88 0 : bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
89 : {
90 0 : if (node->isAssignment())
91 : {
92 0 : mIsValid = false;
93 : }
94 0 : return true;
95 : }
96 :
97 0 : ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
98 : : TIntermTraverser(true, false, false),
99 : mContext(context),
100 : mIsValid(true),
101 0 : mIssueWarning(false)
102 : {
103 0 : }
104 :
105 : } // namespace
106 :
107 0 : bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning)
108 : {
109 0 : ValidateGlobalInitializerTraverser validate(context);
110 0 : initializer->traverse(&validate);
111 0 : ASSERT(warning != nullptr);
112 0 : *warning = validate.issueWarning();
113 0 : return validate.isValid();
114 : }
115 :
116 : } // namespace sh
|