blob: 918cb8526de77285115f2dbec4efb314d1cdd227 [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
11namespace
12{
13
14class ValidateGlobalInitializerTraverser : public TIntermTraverser
15{
16 public:
17 ValidateGlobalInitializerTraverser(const TParseContext *context);
18
19 void visitSymbol(TIntermSymbol *node) override;
Olli Etuahoce39f6f2015-07-06 15:25:19 +030020 bool visitAggregate(Visit visit, TIntermAggregate *node) override;
Olli Etuaho846fe052015-07-07 17:41:21 +030021 bool visitBinary(Visit visit, TIntermBinary *node) override;
22 bool visitUnary(Visit visit, TIntermUnary *node) override;
Olli Etuahob0c645e2015-05-12 14:25:36 +030023
24 bool isValid() const { return mIsValid; }
25 bool issueWarning() const { return mIssueWarning; }
26
27 private:
28 const TParseContext *mContext;
29 bool mIsValid;
30 bool mIssueWarning;
31};
32
33void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
34{
35 const TSymbol *sym = mContext->symbolTable.find(node->getSymbol(), mContext->getShaderVersion());
36 if (sym->isVariable())
37 {
38 // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
39 // Global initializers must be constant expressions.
40 const TVariable *var = static_cast<const TVariable *>(sym);
41 switch (var->getType().getQualifier())
42 {
43 case EvqConst:
44 break;
45 case EvqGlobal:
46 case EvqTemporary:
47 case EvqUniform:
48 // We allow these cases to be compatible with legacy ESSL 1.00 content.
49 // Implement stricter rules for ESSL 3.00 since there's no legacy content to deal with.
50 if (mContext->getShaderVersion() >= 300)
51 {
52 mIsValid = false;
53 }
54 else
55 {
56 mIssueWarning = true;
57 }
58 break;
59 default:
60 mIsValid = false;
61 }
62 }
63}
64
Olli Etuahoce39f6f2015-07-06 15:25:19 +030065bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
66{
67 // Disallow calls to user-defined functions in global variable initializers.
68 if (node->getOp() == EOpFunctionCall && node->isUserDefined())
69 {
70 mIsValid = false;
71 }
72 return true;
73}
74
Olli Etuaho846fe052015-07-07 17:41:21 +030075bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
76{
77 if (node->isAssignment())
78 {
79 mIsValid = false;
80 }
81 return true;
82}
83
84bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
85{
86 if (node->isAssignment())
87 {
88 mIsValid = false;
89 }
90 return true;
91}
92
Olli Etuahob0c645e2015-05-12 14:25:36 +030093ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
94 : TIntermTraverser(true, false, false),
95 mContext(context),
96 mIsValid(true),
97 mIssueWarning(false)
98{
99}
100
101} // namespace
102
103bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning)
104{
105 ValidateGlobalInitializerTraverser validate(context);
106 initializer->traverse(&validate);
107 ASSERT(warning != nullptr);
108 *warning = validate.issueWarning();
109 return validate.isValid();
110}
111