blob: 2461b6a4383bf9611d69e162d883044215169952 [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{
Olli Etuahob5841ef2015-07-08 17:25:22 +030067 // Disallow calls to user-defined functions and texture lookup functions in global variable initializers.
68 // This is done simply by disabling all function calls - built-in math functions don't use EOpFunctionCall.
69 if (node->getOp() == EOpFunctionCall)
Olli Etuahoce39f6f2015-07-06 15:25:19 +030070 {
71 mIsValid = false;
72 }
73 return true;
74}
75
Olli Etuaho846fe052015-07-07 17:41:21 +030076bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
77{
78 if (node->isAssignment())
79 {
80 mIsValid = false;
81 }
82 return true;
83}
84
85bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
86{
87 if (node->isAssignment())
88 {
89 mIsValid = false;
90 }
91 return true;
92}
93
Olli Etuahob0c645e2015-05-12 14:25:36 +030094ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
95 : TIntermTraverser(true, false, false),
96 mContext(context),
97 mIsValid(true),
98 mIssueWarning(false)
99{
100}
101
102} // namespace
103
104bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning)
105{
106 ValidateGlobalInitializerTraverser validate(context);
107 initializer->traverse(&validate);
108 ASSERT(warning != nullptr);
109 *warning = validate.issueWarning();
110 return validate.isValid();
111}
112