blob: d5b1b3be41c910a5131004d2f0a9c94c45128241 [file] [log] [blame]
Olli Etuahob0c645e2015-05-12 14:25:36 +03001//
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
Jamie Madill45bcc782016-11-07 13:58:48 -050011namespace sh
12{
13
Olli Etuahob0c645e2015-05-12 14:25:36 +030014namespace
15{
16
17class ValidateGlobalInitializerTraverser : public TIntermTraverser
18{
19 public:
20 ValidateGlobalInitializerTraverser(const TParseContext *context);
21
22 void visitSymbol(TIntermSymbol *node) override;
Olli Etuahoce39f6f2015-07-06 15:25:19 +030023 bool visitAggregate(Visit visit, TIntermAggregate *node) override;
Olli Etuaho846fe052015-07-07 17:41:21 +030024 bool visitBinary(Visit visit, TIntermBinary *node) override;
25 bool visitUnary(Visit visit, TIntermUnary *node) override;
Olli Etuahob0c645e2015-05-12 14:25:36 +030026
27 bool isValid() const { return mIsValid; }
28 bool issueWarning() const { return mIssueWarning; }
29
30 private:
31 const TParseContext *mContext;
32 bool mIsValid;
33 bool mIssueWarning;
34};
35
36void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
37{
38 const TSymbol *sym = mContext->symbolTable.find(node->getSymbol(), mContext->getShaderVersion());
39 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 const TVariable *var = static_cast<const TVariable *>(sym);
44 switch (var->getType().getQualifier())
45 {
46 case EvqConst:
47 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 if (mContext->getShaderVersion() >= 300)
54 {
55 mIsValid = false;
56 }
57 else
58 {
59 mIssueWarning = true;
60 }
61 break;
62 default:
63 mIsValid = false;
64 }
65 }
66}
67
Olli Etuahoce39f6f2015-07-06 15:25:19 +030068bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
69{
Olli Etuahob5841ef2015-07-08 17:25:22 +030070 // 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 if (node->getOp() == EOpFunctionCall)
Olli Etuahoce39f6f2015-07-06 15:25:19 +030073 {
74 mIsValid = false;
75 }
76 return true;
77}
78
Olli Etuaho846fe052015-07-07 17:41:21 +030079bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
80{
81 if (node->isAssignment())
82 {
83 mIsValid = false;
84 }
85 return true;
86}
87
88bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
89{
90 if (node->isAssignment())
91 {
92 mIsValid = false;
93 }
94 return true;
95}
96
Olli Etuahob0c645e2015-05-12 14:25:36 +030097ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
98 : TIntermTraverser(true, false, false),
99 mContext(context),
100 mIsValid(true),
101 mIssueWarning(false)
102{
103}
104
105} // namespace
106
107bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning)
108{
109 ValidateGlobalInitializerTraverser validate(context);
110 initializer->traverse(&validate);
111 ASSERT(warning != nullptr);
112 *warning = validate.issueWarning();
113 return validate.isValid();
114}
115
Jamie Madill45bcc782016-11-07 13:58:48 -0500116} // namespace sh