| // |
| // Copyright 2002 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| #include "compiler/translator/ValidateGlobalInitializer.h" |
| |
| #include "compiler/translator/tree_util/IntermTraverse.h" |
| |
| namespace sh |
| { |
| |
| namespace |
| { |
| |
| const int kMaxAllowedTraversalDepth = 256; |
| |
| class ValidateGlobalInitializerTraverser : public TIntermTraverser |
| { |
| public: |
| ValidateGlobalInitializerTraverser(int shaderVersion, bool isWebGL); |
| |
| void visitSymbol(TIntermSymbol *node) override; |
| void visitConstantUnion(TIntermConstantUnion *node) override; |
| bool visitAggregate(Visit visit, TIntermAggregate *node) override; |
| bool visitBinary(Visit visit, TIntermBinary *node) override; |
| bool visitUnary(Visit visit, TIntermUnary *node) override; |
| |
| bool isValid() const { return mIsValid && mMaxDepth < mMaxAllowedDepth; } |
| bool issueWarning() const { return mIssueWarning; } |
| |
| private: |
| int mShaderVersion; |
| bool mIsWebGL; |
| bool mIsValid; |
| bool mIssueWarning; |
| }; |
| |
| void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node) |
| { |
| // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3): |
| // Global initializers must be constant expressions. |
| switch (node->getType().getQualifier()) |
| { |
| case EvqConst: |
| break; |
| case EvqGlobal: |
| case EvqTemporary: |
| case EvqUniform: |
| // We allow these cases to be compatible with legacy ESSL 1.00 content. |
| // Implement stricter rules for ESSL 3.00 since there's no legacy content to deal |
| // with. |
| if ((mShaderVersion >= 300) || !mIsWebGL) |
| { |
| mIsValid = false; |
| } |
| else |
| { |
| mIssueWarning = true; |
| } |
| break; |
| default: |
| mIsValid = false; |
| } |
| } |
| |
| void ValidateGlobalInitializerTraverser::visitConstantUnion(TIntermConstantUnion *node) |
| { |
| // Constant unions that are not constant expressions may result from folding a ternary |
| // expression. |
| switch (node->getType().getQualifier()) |
| { |
| case EvqConst: |
| break; |
| case EvqTemporary: |
| if ((mShaderVersion >= 300) || !mIsWebGL) |
| { |
| mIsValid = false; |
| } |
| else |
| { |
| mIssueWarning = true; |
| } |
| break; |
| default: |
| UNREACHABLE(); |
| } |
| } |
| |
| bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node) |
| { |
| // Disallow calls to user-defined functions and texture lookup functions in global variable |
| // initializers. |
| // This is done simply by disabling all function calls - built-in math functions don't use |
| // the function call ops. |
| if (node->isFunctionCall()) |
| { |
| mIsValid = false; |
| } |
| return true; |
| } |
| |
| bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node) |
| { |
| if (node->isAssignment()) |
| { |
| mIsValid = false; |
| } |
| return true; |
| } |
| |
| bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node) |
| { |
| if (node->isAssignment()) |
| { |
| mIsValid = false; |
| } |
| return true; |
| } |
| |
| ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(int shaderVersion, |
| bool isWebGL) |
| : TIntermTraverser(true, false, false, nullptr), |
| mShaderVersion(shaderVersion), |
| mIsWebGL(isWebGL), |
| mIsValid(true), |
| mIssueWarning(false) |
| { |
| setMaxAllowedDepth(kMaxAllowedTraversalDepth); |
| } |
| |
| } // namespace |
| |
| bool ValidateGlobalInitializer(TIntermTyped *initializer, |
| int shaderVersion, |
| bool isWebGL, |
| bool *warning) |
| { |
| ValidateGlobalInitializerTraverser validate(shaderVersion, isWebGL); |
| initializer->traverse(&validate); |
| ASSERT(warning != nullptr); |
| *warning = validate.issueWarning(); |
| return validate.isValid(); |
| } |
| |
| } // namespace sh |