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