From a6a12d8c0fc918972c15268f749ecc7c90b95d6c Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Tue, 5 Aug 2014 12:59:44 +0300 Subject: ANGLE: upgrade to 2.1~07d49ef5350a This version of ANGLE provides partial ES3 support, numerous bug fixes, and several potentially useful vendor extensions. All patches have been rebased. The following changes are noted: 0000-General-fixes-for-ANGLE-2.1.patch contains compile fixes for the new ANGLE 0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch has incorporated patch 0015. 0007-Make-DX9-DX11-mutually-exclusive.patch has been removed as it was fixed upstream. 0007-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch has been moved up to fill the patch number gap. 0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch now contains patch 0014 and 0017. 0013-ANGLE-Allow-for-universal-program-binaries.patch has been removed as it is no longer relevant. 0014-ANGLE-D3D11-Fix-internal-index-buffer-for-level-9-ha.patch has been merged with patch 0010. 0015-ANGLE-Don-t-export-DLLMain-functions-for-static-buil.patch has been merged with patch 0004. 0016-ANGLE-WinRT-Call-Trim-when-application-suspends.patch has been removed and will be replaced by a follow-up patch using a different technique. 0017-ANGLE-D3D11-Don-t-use-mipmaps-in-level-9-textures.patch has been merged with patch 0010. 0018-ANGLE-WinRT-Create-swap-chain-using-physical-resolut.patch has been removed and will be replaced by a follow-up patch extending the EGL_ANGLE_window_fixed_size extension. 0019-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch is now patch 0007. [ChangeLog][Third-party libraries] ANGLE has been upgraded to version 2.1, bringing partial support for OpenGL ES3 over Direct3D 11, numerous bug fixes, and several new vendor extensions. Change-Id: I6d95ce1480462d67228d83c1e5c74a1706b5b21c Reviewed-by: Friedemann Kleint --- .../src/compiler/preprocessor/DiagnosticsBase.cpp | 80 +- .../src/compiler/preprocessor/DiagnosticsBase.h | 6 +- .../compiler/preprocessor/DirectiveHandlerBase.h | 18 +- .../src/compiler/preprocessor/DirectiveParser.cpp | 171 +- .../src/compiler/preprocessor/DirectiveParser.h | 62 +- .../src/compiler/preprocessor/ExpressionParser.h | 8 +- .../src/compiler/preprocessor/ExpressionParser.y | 85 +- .../angle/src/compiler/preprocessor/Input.cpp | 4 +- .../angle/src/compiler/preprocessor/Input.h | 29 +- .../angle/src/compiler/preprocessor/Lexer.h | 2 +- .../angle/src/compiler/preprocessor/Macro.cpp | 2 +- .../angle/src/compiler/preprocessor/Macro.h | 9 +- .../src/compiler/preprocessor/MacroExpander.cpp | 64 +- .../src/compiler/preprocessor/MacroExpander.h | 60 +- .../src/compiler/preprocessor/Preprocessor.cpp | 35 +- .../angle/src/compiler/preprocessor/Preprocessor.h | 19 +- .../src/compiler/preprocessor/SourceLocation.h | 18 +- .../angle/src/compiler/preprocessor/Token.cpp | 10 +- .../angle/src/compiler/preprocessor/Token.h | 35 +- .../angle/src/compiler/preprocessor/Tokenizer.h | 16 +- .../angle/src/compiler/preprocessor/Tokenizer.l | 34 +- .../src/compiler/preprocessor/length_limits.h | 21 - .../angle/src/compiler/preprocessor/numeric_lex.h | 8 +- .../angle/src/compiler/preprocessor/pp_utils.h | 4 +- .../angle/src/compiler/translator/BaseTypes.h | 352 ++- .../translator/BuiltInFunctionEmulator.cpp | 16 +- .../compiler/translator/BuiltInFunctionEmulator.h | 4 +- .../angle/src/compiler/translator/CodeGen.cpp | 14 +- .../angle/src/compiler/translator/Compiler.cpp | 234 +- .../angle/src/compiler/translator/Compiler.h | 191 ++ .../angle/src/compiler/translator/ConstantUnion.h | 94 +- .../src/compiler/translator/DetectCallDepth.h | 2 - .../angle/src/compiler/translator/Diagnostics.cpp | 2 +- .../angle/src/compiler/translator/Diagnostics.h | 2 +- .../src/compiler/translator/DirectiveHandler.cpp | 17 +- .../src/compiler/translator/DirectiveHandler.h | 4 +- .../src/compiler/translator/FlagStd140Structs.cpp | 77 + .../src/compiler/translator/FlagStd140Structs.h | 37 + .../src/compiler/translator/ForLoopUnroll.cpp | 245 +- .../angle/src/compiler/translator/ForLoopUnroll.h | 78 +- .../angle/src/compiler/translator/HashNames.h | 1 - .../angle/src/compiler/translator/Initialize.cpp | 983 ++++--- .../angle/src/compiler/translator/Initialize.h | 6 +- .../src/compiler/translator/InitializeDll.cpp | 6 +- .../compiler/translator/InitializeParseContext.cpp | 26 +- .../compiler/translator/InitializeVariables.cpp | 24 +- .../src/compiler/translator/InitializeVariables.h | 16 +- .../src/compiler/translator/IntermTraverse.cpp | 120 +- .../angle/src/compiler/translator/Intermediate.cpp | 1915 +++++++------- .../angle/src/compiler/translator/LoopInfo.cpp | 211 ++ .../angle/src/compiler/translator/LoopInfo.h | 80 + .../compiler/translator/MapLongVariableNames.cpp | 115 - .../src/compiler/translator/MapLongVariableNames.h | 58 - .../angle/src/compiler/translator/OutputESSL.cpp | 7 +- .../angle/src/compiler/translator/OutputESSL.h | 5 +- .../angle/src/compiler/translator/OutputGLSL.cpp | 28 +- .../angle/src/compiler/translator/OutputGLSL.h | 6 +- .../src/compiler/translator/OutputGLSLBase.cpp | 1094 ++++---- .../angle/src/compiler/translator/OutputGLSLBase.h | 82 +- .../angle/src/compiler/translator/OutputHLSL.cpp | 2762 +++++++++----------- .../angle/src/compiler/translator/OutputHLSL.h | 118 +- .../angle/src/compiler/translator/ParseContext.cpp | 1446 ++++++++-- .../angle/src/compiler/translator/ParseContext.h | 63 +- .../angle/src/compiler/translator/PoolAlloc.cpp | 35 +- .../angle/src/compiler/translator/RemoveTree.cpp | 70 +- .../src/compiler/translator/RewriteElseBlocks.cpp | 92 +- .../src/compiler/translator/RewriteElseBlocks.h | 17 - .../ScalarizeVecAndMatConstructorArgs.cpp | 266 ++ .../translator/ScalarizeVecAndMatConstructorArgs.h | 41 + .../angle/src/compiler/translator/ShHandle.h | 179 -- .../angle/src/compiler/translator/ShaderLang.cpp | 234 +- .../src/compiler/translator/StructureHLSL.cpp | 477 ++++ .../angle/src/compiler/translator/StructureHLSL.h | 74 + .../angle/src/compiler/translator/SymbolTable.cpp | 316 +-- .../angle/src/compiler/translator/SymbolTable.h | 455 ++-- .../src/compiler/translator/TranslatorESSL.cpp | 11 +- .../angle/src/compiler/translator/TranslatorESSL.h | 4 +- .../src/compiler/translator/TranslatorGLSL.cpp | 30 +- .../angle/src/compiler/translator/TranslatorGLSL.h | 7 +- .../src/compiler/translator/TranslatorHLSL.cpp | 38 +- .../angle/src/compiler/translator/TranslatorHLSL.h | 25 +- .../angle/src/compiler/translator/Types.cpp | 202 ++ src/3rdparty/angle/src/compiler/translator/Types.h | 527 +++- .../src/compiler/translator/UnfoldShortCircuit.cpp | 3 +- .../angle/src/compiler/translator/Uniform.cpp | 21 - .../angle/src/compiler/translator/Uniform.h | 35 - .../angle/src/compiler/translator/UniformHLSL.cpp | 291 +++ .../angle/src/compiler/translator/UniformHLSL.h | 66 + .../angle/src/compiler/translator/UtilsHLSL.cpp | 243 ++ .../angle/src/compiler/translator/UtilsHLSL.h | 37 + .../compiler/translator/ValidateLimitations.cpp | 428 +-- .../src/compiler/translator/ValidateLimitations.h | 58 +- .../src/compiler/translator/ValidateOutputs.cpp | 78 + .../src/compiler/translator/ValidateOutputs.h | 33 + .../angle/src/compiler/translator/VariableInfo.cpp | 553 ++-- .../angle/src/compiler/translator/VariableInfo.h | 58 +- .../src/compiler/translator/VariablePacker.cpp | 190 +- .../angle/src/compiler/translator/VariablePacker.h | 14 +- .../angle/src/compiler/translator/VersionGLSL.cpp | 111 +- .../angle/src/compiler/translator/VersionGLSL.h | 32 +- .../translator/depgraph/DependencyGraphBuilder.cpp | 164 +- .../translator/depgraph/DependencyGraphBuilder.h | 194 +- .../angle/src/compiler/translator/glslang.l | 385 ++- .../angle/src/compiler/translator/glslang.y | 757 +++--- .../angle/src/compiler/translator/intermOut.cpp | 608 +++-- .../angle/src/compiler/translator/intermediate.h | 626 +++-- .../angle/src/compiler/translator/length_limits.h | 21 + .../src/compiler/translator/localintermediate.h | 86 +- .../angle/src/compiler/translator/osinclude.h | 64 - .../src/compiler/translator/ossource_posix.cpp | 72 - .../angle/src/compiler/translator/ossource_win.cpp | 65 - .../src/compiler/translator/ossource_winrt.cpp | 75 - .../angle/src/compiler/translator/parseConst.cpp | 269 +- .../timing/RestrictFragmentShaderTiming.cpp | 9 + .../timing/RestrictFragmentShaderTiming.h | 2 - .../timing/RestrictVertexShaderTiming.cpp | 2 +- .../translator/timing/RestrictVertexShaderTiming.h | 2 - .../angle/src/compiler/translator/util.cpp | 328 +++ src/3rdparty/angle/src/compiler/translator/util.h | 46 + 119 files changed, 12652 insertions(+), 7815 deletions(-) delete mode 100644 src/3rdparty/angle/src/compiler/preprocessor/length_limits.h create mode 100644 src/3rdparty/angle/src/compiler/translator/Compiler.h create mode 100644 src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h create mode 100644 src/3rdparty/angle/src/compiler/translator/LoopInfo.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/LoopInfo.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/MapLongVariableNames.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/MapLongVariableNames.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/ShHandle.h create mode 100644 src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/StructureHLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/Types.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/Uniform.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/Uniform.h create mode 100644 src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/UniformHLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h create mode 100644 src/3rdparty/angle/src/compiler/translator/length_limits.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/osinclude.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/ossource_posix.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/ossource_win.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/ossource_winrt.cpp (limited to 'src/3rdparty/angle/src/compiler') diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp index a7ce862bcb..cf60bc2349 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp @@ -16,8 +16,8 @@ Diagnostics::~Diagnostics() } void Diagnostics::report(ID id, - const SourceLocation& loc, - const std::string& text) + const SourceLocation &loc, + const std::string &text) { // TODO(alokp): Keep a count of errors and warnings. print(id, loc, text); @@ -41,86 +41,86 @@ std::string Diagnostics::message(ID id) { // Errors begin. case PP_INTERNAL_ERROR: - return "internal error"; + return "internal error"; case PP_OUT_OF_MEMORY: - return "out of memory"; + return "out of memory"; case PP_INVALID_CHARACTER: - return "invalid character"; + return "invalid character"; case PP_INVALID_NUMBER: - return "invalid number"; + return "invalid number"; case PP_INTEGER_OVERFLOW: - return "integer overflow"; + return "integer overflow"; case PP_FLOAT_OVERFLOW: - return "float overflow"; + return "float overflow"; case PP_TOKEN_TOO_LONG: - return "token too long"; + return "token too long"; case PP_INVALID_EXPRESSION: - return "invalid expression"; + return "invalid expression"; case PP_DIVISION_BY_ZERO: - return "division by zero"; + return "division by zero"; case PP_EOF_IN_COMMENT: - return "unexpected end of file found in comment"; + return "unexpected end of file found in comment"; case PP_UNEXPECTED_TOKEN: - return "unexpected token"; + return "unexpected token"; case PP_DIRECTIVE_INVALID_NAME: - return "invalid directive name"; + return "invalid directive name"; case PP_MACRO_NAME_RESERVED: - return "macro name is reserved"; + return "macro name is reserved"; case PP_MACRO_REDEFINED: - return "macro redefined"; + return "macro redefined"; case PP_MACRO_PREDEFINED_REDEFINED: - return "predefined macro redefined"; + return "predefined macro redefined"; case PP_MACRO_PREDEFINED_UNDEFINED: - return "predefined macro undefined"; + return "predefined macro undefined"; case PP_MACRO_UNTERMINATED_INVOCATION: - return "unterminated macro invocation"; + return "unterminated macro invocation"; case PP_MACRO_TOO_FEW_ARGS: - return "Not enough arguments for macro"; + return "Not enough arguments for macro"; case PP_MACRO_TOO_MANY_ARGS: - return "Too many arguments for macro"; + return "Too many arguments for macro"; case PP_CONDITIONAL_ENDIF_WITHOUT_IF: - return "unexpected #endif found without a matching #if"; + return "unexpected #endif found without a matching #if"; case PP_CONDITIONAL_ELSE_WITHOUT_IF: - return "unexpected #else found without a matching #if"; + return "unexpected #else found without a matching #if"; case PP_CONDITIONAL_ELSE_AFTER_ELSE: - return "unexpected #else found after another #else"; + return "unexpected #else found after another #else"; case PP_CONDITIONAL_ELIF_WITHOUT_IF: - return "unexpected #elif found without a matching #if"; + return "unexpected #elif found without a matching #if"; case PP_CONDITIONAL_ELIF_AFTER_ELSE: - return "unexpected #elif found after #else"; + return "unexpected #elif found after #else"; case PP_CONDITIONAL_UNTERMINATED: - return "unexpected end of file found in conditional block"; + return "unexpected end of file found in conditional block"; case PP_INVALID_EXTENSION_NAME: - return "invalid extension name"; + return "invalid extension name"; case PP_INVALID_EXTENSION_BEHAVIOR: - return "invalid extension behavior"; + return "invalid extension behavior"; case PP_INVALID_EXTENSION_DIRECTIVE: - return "invalid extension directive"; + return "invalid extension directive"; case PP_INVALID_VERSION_NUMBER: - return "invalid version number"; + return "invalid version number"; case PP_INVALID_VERSION_DIRECTIVE: - return "invalid version directive"; + return "invalid version directive"; case PP_VERSION_NOT_FIRST_STATEMENT: return "#version directive must occur before anything else, " "except for comments and white space"; case PP_INVALID_LINE_NUMBER: - return "invalid line number"; + return "invalid line number"; case PP_INVALID_FILE_NUMBER: - return "invalid file number"; + return "invalid file number"; case PP_INVALID_LINE_DIRECTIVE: - return "invalid line directive"; + return "invalid line directive"; // Errors end. // Warnings begin. case PP_EOF_IN_DIRECTIVE: - return "unexpected end of file found in directive"; + return "unexpected end of file found in directive"; case PP_CONDITIONAL_UNEXPECTED_TOKEN: - return "unexpected token after conditional expression"; + return "unexpected token after conditional expression"; case PP_UNRECOGNIZED_PRAGMA: - return "unrecognized pragma"; + return "unrecognized pragma"; // Warnings end. default: - assert(false); - return ""; + assert(false); + return ""; } } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h index 2c8c539137..a7587ed657 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h @@ -72,15 +72,15 @@ class Diagnostics virtual ~Diagnostics(); - void report(ID id, const SourceLocation& loc, const std::string& text); + void report(ID id, const SourceLocation &loc, const std::string &text); protected: Severity severity(ID id); std::string message(ID id); virtual void print(ID id, - const SourceLocation& loc, - const std::string& text) = 0; + const SourceLocation &loc, + const std::string &text) = 0; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h index 2aaeec2818..040b25c6a2 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h @@ -23,19 +23,19 @@ class DirectiveHandler public: virtual ~DirectiveHandler(); - virtual void handleError(const SourceLocation& loc, - const std::string& msg) = 0; + virtual void handleError(const SourceLocation &loc, + const std::string &msg) = 0; // Handle pragma of form: #pragma name[(value)] - virtual void handlePragma(const SourceLocation& loc, - const std::string& name, - const std::string& value) = 0; + virtual void handlePragma(const SourceLocation &loc, + const std::string &name, + const std::string &value) = 0; - virtual void handleExtension(const SourceLocation& loc, - const std::string& name, - const std::string& behavior) = 0; + virtual void handleExtension(const SourceLocation &loc, + const std::string &name, + const std::string &behavior) = 0; - virtual void handleVersion(const SourceLocation& loc, + virtual void handleVersion(const SourceLocation &loc, int version) = 0; }; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp index ebec79804d..6434d5cb5c 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2011-2013 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. // @@ -35,9 +35,8 @@ enum DirectiveType DIRECTIVE_VERSION, DIRECTIVE_LINE }; -} // namespace -static DirectiveType getDirective(const pp::Token* token) +DirectiveType getDirective(const pp::Token *token) { static const std::string kDirectiveDefine("define"); static const std::string kDirectiveUndef("undef"); @@ -58,35 +57,35 @@ static DirectiveType getDirective(const pp::Token* token) if (token->text == kDirectiveDefine) return DIRECTIVE_DEFINE; - else if (token->text == kDirectiveUndef) + if (token->text == kDirectiveUndef) return DIRECTIVE_UNDEF; - else if (token->text == kDirectiveIf) + if (token->text == kDirectiveIf) return DIRECTIVE_IF; - else if (token->text == kDirectiveIfdef) + if (token->text == kDirectiveIfdef) return DIRECTIVE_IFDEF; - else if (token->text == kDirectiveIfndef) + if (token->text == kDirectiveIfndef) return DIRECTIVE_IFNDEF; - else if (token->text == kDirectiveElse) + if (token->text == kDirectiveElse) return DIRECTIVE_ELSE; - else if (token->text == kDirectiveElif) + if (token->text == kDirectiveElif) return DIRECTIVE_ELIF; - else if (token->text == kDirectiveEndif) + if (token->text == kDirectiveEndif) return DIRECTIVE_ENDIF; - else if (token->text == kDirectiveError) + if (token->text == kDirectiveError) return DIRECTIVE_ERROR; - else if (token->text == kDirectivePragma) + if (token->text == kDirectivePragma) return DIRECTIVE_PRAGMA; - else if (token->text == kDirectiveExtension) + if (token->text == kDirectiveExtension) return DIRECTIVE_EXTENSION; - else if (token->text == kDirectiveVersion) + if (token->text == kDirectiveVersion) return DIRECTIVE_VERSION; - else if (token->text == kDirectiveLine) + if (token->text == kDirectiveLine) return DIRECTIVE_LINE; return DIRECTIVE_NONE; } -static bool isConditionalDirective(DirectiveType directive) +bool isConditionalDirective(DirectiveType directive) { switch (directive) { @@ -103,12 +102,12 @@ static bool isConditionalDirective(DirectiveType directive) } // Returns true if the token represents End Of Directive. -static bool isEOD(const pp::Token* token) +bool isEOD(const pp::Token *token) { return (token->type == '\n') || (token->type == pp::Token::LAST); } -static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token) +void skipUntilEOD(pp::Lexer *lexer, pp::Token *token) { while(!isEOD(token)) { @@ -116,7 +115,7 @@ static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token) } } -static bool isMacroNameReserved(const std::string& name) +bool isMacroNameReserved(const std::string &name) { // Names prefixed with "GL_" are reserved. if (name.substr(0, 3) == "GL_") @@ -129,30 +128,32 @@ static bool isMacroNameReserved(const std::string& name) return false; } -static bool isMacroPredefined(const std::string& name, - const pp::MacroSet& macroSet) +bool isMacroPredefined(const std::string &name, + const pp::MacroSet ¯oSet) { pp::MacroSet::const_iterator iter = macroSet.find(name); return iter != macroSet.end() ? iter->second.predefined : false; } +} // namespace anonymous + namespace pp { class DefinedParser : public Lexer { public: - DefinedParser(Lexer* lexer, - const MacroSet* macroSet, - Diagnostics* diagnostics) : - mLexer(lexer), - mMacroSet(macroSet), - mDiagnostics(diagnostics) + DefinedParser(Lexer *lexer, + const MacroSet *macroSet, + Diagnostics *diagnostics) + : mLexer(lexer), + mMacroSet(macroSet), + mDiagnostics(diagnostics) { } protected: - virtual void lex(Token* token) + virtual void lex(Token *token) { static const std::string kDefined("defined"); @@ -199,24 +200,24 @@ class DefinedParser : public Lexer } private: - Lexer* mLexer; - const MacroSet* mMacroSet; - Diagnostics* mDiagnostics; + Lexer *mLexer; + const MacroSet *mMacroSet; + Diagnostics *mDiagnostics; }; -DirectiveParser::DirectiveParser(Tokenizer* tokenizer, - MacroSet* macroSet, - Diagnostics* diagnostics, - DirectiveHandler* directiveHandler) : - mPastFirstStatement(false), - mTokenizer(tokenizer), - mMacroSet(macroSet), - mDiagnostics(diagnostics), - mDirectiveHandler(directiveHandler) +DirectiveParser::DirectiveParser(Tokenizer *tokenizer, + MacroSet *macroSet, + Diagnostics *diagnostics, + DirectiveHandler *directiveHandler) + : mPastFirstStatement(false), + mTokenizer(tokenizer), + mMacroSet(macroSet), + mDiagnostics(diagnostics), + mDirectiveHandler(directiveHandler) { } -void DirectiveParser::lex(Token* token) +void DirectiveParser::lex(Token *token) { do { @@ -232,19 +233,20 @@ void DirectiveParser::lex(Token* token) { if (!mConditionalStack.empty()) { - const ConditionalBlock& block = mConditionalStack.back(); + const ConditionalBlock &block = mConditionalStack.back(); mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location, block.type); } break; } - } while (skipping() || (token->type == '\n')); + } + while (skipping() || (token->type == '\n')); mPastFirstStatement = true; } -void DirectiveParser::parseDirective(Token* token) +void DirectiveParser::parseDirective(Token *token) { assert(token->type == Token::PP_HASH); @@ -324,7 +326,7 @@ void DirectiveParser::parseDirective(Token* token) } } -void DirectiveParser::parseDefine(Token* token) +void DirectiveParser::parseDefine(Token *token) { assert(getDirective(token) == DIRECTIVE_DEFINE); @@ -357,14 +359,16 @@ void DirectiveParser::parseDefine(Token* token) { // Function-like macro. Collect arguments. macro.type = Macro::kTypeFunc; - do { + do + { mTokenizer->lex(token); if (token->type != Token::IDENTIFIER) break; macro.parameters.push_back(token->text); mTokenizer->lex(token); // Get ','. - } while (token->type == ','); + } + while (token->type == ','); if (token->type != ')') { @@ -404,7 +408,7 @@ void DirectiveParser::parseDefine(Token* token) mMacroSet->insert(std::make_pair(macro.name, macro)); } -void DirectiveParser::parseUndef(Token* token) +void DirectiveParser::parseUndef(Token *token) { assert(getDirective(token) == DIRECTIVE_UNDEF); @@ -433,25 +437,25 @@ void DirectiveParser::parseUndef(Token* token) mTokenizer->lex(token); } -void DirectiveParser::parseIf(Token* token) +void DirectiveParser::parseIf(Token *token) { assert(getDirective(token) == DIRECTIVE_IF); parseConditionalIf(token); } -void DirectiveParser::parseIfdef(Token* token) +void DirectiveParser::parseIfdef(Token *token) { assert(getDirective(token) == DIRECTIVE_IFDEF); parseConditionalIf(token); } -void DirectiveParser::parseIfndef(Token* token) +void DirectiveParser::parseIfndef(Token *token) { assert(getDirective(token) == DIRECTIVE_IFNDEF); parseConditionalIf(token); } -void DirectiveParser::parseElse(Token* token) +void DirectiveParser::parseElse(Token *token) { assert(getDirective(token) == DIRECTIVE_ELSE); @@ -463,7 +467,7 @@ void DirectiveParser::parseElse(Token* token) return; } - ConditionalBlock& block = mConditionalStack.back(); + ConditionalBlock &block = mConditionalStack.back(); if (block.skipBlock) { // No diagnostics. Just skip the whole line. @@ -492,7 +496,7 @@ void DirectiveParser::parseElse(Token* token) } } -void DirectiveParser::parseElif(Token* token) +void DirectiveParser::parseElif(Token *token) { assert(getDirective(token) == DIRECTIVE_ELIF); @@ -504,7 +508,7 @@ void DirectiveParser::parseElif(Token* token) return; } - ConditionalBlock& block = mConditionalStack.back(); + ConditionalBlock &block = mConditionalStack.back(); if (block.skipBlock) { // No diagnostics. Just skip the whole line. @@ -532,7 +536,7 @@ void DirectiveParser::parseElif(Token* token) block.foundValidGroup = expression != 0; } -void DirectiveParser::parseEndif(Token* token) +void DirectiveParser::parseEndif(Token *token) { assert(getDirective(token) == DIRECTIVE_ENDIF); @@ -556,7 +560,7 @@ void DirectiveParser::parseEndif(Token* token) } } -void DirectiveParser::parseError(Token* token) +void DirectiveParser::parseError(Token *token) { assert(getDirective(token) == DIRECTIVE_ERROR); @@ -571,7 +575,7 @@ void DirectiveParser::parseError(Token* token) } // Parses pragma of form: #pragma name[(value)]. -void DirectiveParser::parsePragma(Token* token) +void DirectiveParser::parsePragma(Token *token) { assert(getDirective(token) == DIRECTIVE_PRAGMA); @@ -627,7 +631,7 @@ void DirectiveParser::parsePragma(Token* token) } } -void DirectiveParser::parseExtension(Token* token) +void DirectiveParser::parseExtension(Token *token) { assert(getDirective(token) == DIRECTIVE_EXTENSION); @@ -694,7 +698,7 @@ void DirectiveParser::parseExtension(Token* token) mDirectiveHandler->handleExtension(token->location, name, behavior); } -void DirectiveParser::parseVersion(Token* token) +void DirectiveParser::parseVersion(Token *token) { assert(getDirective(token) == DIRECTIVE_VERSION); @@ -708,7 +712,9 @@ void DirectiveParser::parseVersion(Token* token) enum State { - VERSION_NUMBER + VERSION_NUMBER, + VERSION_PROFILE, + VERSION_ENDLINE }; bool valid = true; @@ -716,12 +722,12 @@ void DirectiveParser::parseVersion(Token* token) int state = VERSION_NUMBER; mTokenizer->lex(token); - while ((token->type != '\n') && (token->type != Token::LAST)) + while (valid && (token->type != '\n') && (token->type != Token::LAST)) { - switch (state++) + switch (state) { case VERSION_NUMBER: - if (valid && (token->type != Token::CONST_INT)) + if (token->type != Token::CONST_INT) { mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location, token->text); @@ -733,29 +739,44 @@ void DirectiveParser::parseVersion(Token* token) token->location, token->text); valid = false; } - break; - default: if (valid) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, + state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE; + } + break; + case VERSION_PROFILE: + if (token->type != Token::IDENTIFIER || token->text != "es") + { + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location, token->text); valid = false; } + state = VERSION_ENDLINE; + break; + default: + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, + token->location, token->text); + valid = false; break; } + mTokenizer->lex(token); } - if (valid && (state != VERSION_NUMBER + 1)) + + if (valid && (state != VERSION_ENDLINE)) { mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location, token->text); valid = false; } + if (valid) + { mDirectiveHandler->handleVersion(token->location, version); + } } -void DirectiveParser::parseLine(Token* token) +void DirectiveParser::parseLine(Token *token) { assert(getDirective(token) == DIRECTIVE_LINE); @@ -824,19 +845,21 @@ void DirectiveParser::parseLine(Token* token) if (valid) { mTokenizer->setLineNumber(line); - if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file); + if (state == FILE_NUMBER + 1) + mTokenizer->setFileNumber(file); } } bool DirectiveParser::skipping() const { - if (mConditionalStack.empty()) return false; + if (mConditionalStack.empty()) + return false; const ConditionalBlock& block = mConditionalStack.back(); return block.skipBlock || block.skipGroup; } -void DirectiveParser::parseConditionalIf(Token* token) +void DirectiveParser::parseConditionalIf(Token *token) { ConditionalBlock block; block.type = token->text; @@ -877,7 +900,7 @@ void DirectiveParser::parseConditionalIf(Token* token) mConditionalStack.push_back(block); } -int DirectiveParser::parseExpressionIf(Token* token) +int DirectiveParser::parseExpressionIf(Token *token) { assert((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF)); @@ -901,7 +924,7 @@ int DirectiveParser::parseExpressionIf(Token* token) return expression; } -int DirectiveParser::parseExpressionIfdef(Token* token) +int DirectiveParser::parseExpressionIfdef(Token *token) { assert((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF)); diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h index 8a7f0072ba..335091781c 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h @@ -22,35 +22,35 @@ class Tokenizer; class DirectiveParser : public Lexer { public: - DirectiveParser(Tokenizer* tokenizer, - MacroSet* macroSet, - Diagnostics* diagnostics, - DirectiveHandler* directiveHandler); + DirectiveParser(Tokenizer *tokenizer, + MacroSet *macroSet, + Diagnostics *diagnostics, + DirectiveHandler *directiveHandler); - virtual void lex(Token* token); + virtual void lex(Token *token); private: PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser); - void parseDirective(Token* token); - void parseDefine(Token* token); - void parseUndef(Token* token); - void parseIf(Token* token); - void parseIfdef(Token* token); - void parseIfndef(Token* token); - void parseElse(Token* token); - void parseElif(Token* token); - void parseEndif(Token* token); - void parseError(Token* token); - void parsePragma(Token* token); - void parseExtension(Token* token); - void parseVersion(Token* token); - void parseLine(Token* token); + void parseDirective(Token *token); + void parseDefine(Token *token); + void parseUndef(Token *token); + void parseIf(Token *token); + void parseIfdef(Token *token); + void parseIfndef(Token *token); + void parseElse(Token *token); + void parseElif(Token *token); + void parseEndif(Token *token); + void parseError(Token *token); + void parsePragma(Token *token); + void parseExtension(Token *token); + void parseVersion(Token *token); + void parseLine(Token *token); bool skipping() const; - void parseConditionalIf(Token* token); - int parseExpressionIf(Token* token); - int parseExpressionIfdef(Token* token); + void parseConditionalIf(Token *token); + int parseExpressionIf(Token *token); + int parseExpressionIfdef(Token *token); struct ConditionalBlock { @@ -61,20 +61,20 @@ class DirectiveParser : public Lexer bool foundValidGroup; bool foundElseGroup; - ConditionalBlock() : - skipBlock(false), - skipGroup(false), - foundValidGroup(false), - foundElseGroup(false) + ConditionalBlock() + : skipBlock(false), + skipGroup(false), + foundValidGroup(false), + foundElseGroup(false) { } }; bool mPastFirstStatement; std::vector mConditionalStack; - Tokenizer* mTokenizer; - MacroSet* mMacroSet; - Diagnostics* mDiagnostics; - DirectiveHandler* mDirectiveHandler; + Tokenizer *mTokenizer; + MacroSet *mMacroSet; + Diagnostics *mDiagnostics; + DirectiveHandler *mDirectiveHandler; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h index 092d059413..f040cb01fa 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h @@ -19,15 +19,15 @@ struct Token; class ExpressionParser { public: - ExpressionParser(Lexer* lexer, Diagnostics* diagnostics); + ExpressionParser(Lexer *lexer, Diagnostics *diagnostics); - bool parse(Token* token, int* result); + bool parse(Token *token, int *result); private: PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser); - Lexer* mLexer; - Diagnostics* mDiagnostics; + Lexer *mLexer; + Diagnostics *mDiagnostics; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y index 9fa0f0bf80..662a31b650 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y @@ -195,15 +195,14 @@ expression %% -int yylex(YYSTYPE* lvalp, Context* context) +int yylex(YYSTYPE *lvalp, Context *context) { int type = 0; - pp::Token* token = context->token; + pp::Token *token = context->token; switch (token->type) { - case pp::Token::CONST_INT: - { + case pp::Token::CONST_INT: { unsigned int val = 0; if (!token->uValue(&val)) { @@ -214,39 +213,59 @@ int yylex(YYSTYPE* lvalp, Context* context) type = TOK_CONST_INT; break; } - case pp::Token::OP_OR: type = TOK_OP_OR; break; - case pp::Token::OP_AND: type = TOK_OP_AND; break; - case pp::Token::OP_NE: type = TOK_OP_NE; break; - case pp::Token::OP_EQ: type = TOK_OP_EQ; break; - case pp::Token::OP_GE: type = TOK_OP_GE; break; - case pp::Token::OP_LE: type = TOK_OP_LE; break; - case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break; - case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break; - case '|': type = '|'; break; - case '^': type = '^'; break; - case '&': type = '&'; break; - case '>': type = '>'; break; - case '<': type = '<'; break; - case '-': type = '-'; break; - case '+': type = '+'; break; - case '%': type = '%'; break; - case '/': type = '/'; break; - case '*': type = '*'; break; - case '!': type = '!'; break; - case '~': type = '~'; break; - case '(': type = '('; break; - case ')': type = ')'; break; + case pp::Token::OP_OR: + type = TOK_OP_OR; + break; + case pp::Token::OP_AND: + type = TOK_OP_AND; + break; + case pp::Token::OP_NE: + type = TOK_OP_NE; + break; + case pp::Token::OP_EQ: + type = TOK_OP_EQ; + break; + case pp::Token::OP_GE: + type = TOK_OP_GE; + break; + case pp::Token::OP_LE: + type = TOK_OP_LE; + break; + case pp::Token::OP_RIGHT: + type = TOK_OP_RIGHT; + break; + case pp::Token::OP_LEFT: + type = TOK_OP_LEFT; + break; + case '|': + case '^': + case '&': + case '>': + case '<': + case '-': + case '+': + case '%': + case '/': + case '*': + case '!': + case '~': + case '(': + case ')': + type = token->type; + break; - default: break; + default: + break; } // Advance to the next token if the current one is valid. - if (type != 0) context->lexer->lex(token); + if (type != 0) + context->lexer->lex(token); return type; } -void yyerror(Context* context, const char* reason) +void yyerror(Context *context, const char *reason) { context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION, context->token->location, @@ -255,13 +274,13 @@ void yyerror(Context* context, const char* reason) namespace pp { -ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) : - mLexer(lexer), - mDiagnostics(diagnostics) +ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics) + : mLexer(lexer), + mDiagnostics(diagnostics) { } -bool ExpressionParser::parse(Token* token, int* result) +bool ExpressionParser::parse(Token *token, int *result) { Context context; context.diagnostics = mDiagnostics; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp index b4d970a97d..f9910a6cc3 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp @@ -17,7 +17,7 @@ Input::Input() : mCount(0), mString(0) { } -Input::Input(size_t count, const char* const string[], const int length[]) : +Input::Input(size_t count, const char *const string[], const int length[]) : mCount(count), mString(string) { @@ -29,7 +29,7 @@ Input::Input(size_t count, const char* const string[], const int length[]) : } } -size_t Input::read(char* buf, size_t maxSize) +size_t Input::read(char *buf, size_t maxSize) { size_t nRead = 0; while ((nRead < maxSize) && (mReadLoc.sIndex < mCount)) diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.h b/src/3rdparty/angle/src/compiler/preprocessor/Input.h index 14b7597cb4..2ac4f0c170 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Input.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.h @@ -18,27 +18,40 @@ class Input { public: Input(); - Input(size_t count, const char* const string[], const int length[]); + Input(size_t count, const char *const string[], const int length[]); - size_t count() const { return mCount; } - const char* string(size_t index) const { return mString[index]; } - size_t length(size_t index) const { return mLength[index]; } + size_t count() const + { + return mCount; + } + const char *string(size_t index) const + { + return mString[index]; + } + size_t length(size_t index) const + { + return mLength[index]; + } - size_t read(char* buf, size_t maxSize); + size_t read(char *buf, size_t maxSize); struct Location { size_t sIndex; // String index; size_t cIndex; // Char index. - Location() : sIndex(0), cIndex(0) { } + Location() + : sIndex(0), + cIndex(0) + { + } }; - const Location& readLoc() const { return mReadLoc; } + const Location &readLoc() const { return mReadLoc; } private: // Input. size_t mCount; - const char* const* mString; + const char * const *mString; std::vector mLength; Location mReadLoc; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h index eb85cea873..d42d3db7e0 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h @@ -17,7 +17,7 @@ class Lexer public: virtual ~Lexer(); - virtual void lex(Token* token) = 0; + virtual void lex(Token *token) = 0; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp index b2e3088e32..13cb14e3dc 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp @@ -11,7 +11,7 @@ namespace pp { -bool Macro::equals(const Macro& other) const +bool Macro::equals(const Macro &other) const { return (type == other.type) && (name == other.name) && diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h index 7ec0149116..b77e7bc15c 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h @@ -26,8 +26,13 @@ struct Macro typedef std::vector Parameters; typedef std::vector Replacements; - Macro() : predefined(false), disabled(false), type(kTypeObj) { } - bool equals(const Macro& other) const; + Macro() + : predefined(false), + disabled(false), + type(kTypeObj) + { + } + bool equals(const Macro &other) const; bool predefined; mutable bool disabled; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp index b789260af9..d7e0c83465 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp @@ -20,13 +20,13 @@ class TokenLexer : public Lexer public: typedef std::vector TokenVector; - TokenLexer(TokenVector* tokens) + TokenLexer(TokenVector *tokens) { tokens->swap(mTokens); mIter = mTokens.begin(); } - virtual void lex(Token* token) + virtual void lex(Token *token) { if (mIter == mTokens.end()) { @@ -46,12 +46,12 @@ class TokenLexer : public Lexer TokenVector::const_iterator mIter; }; -MacroExpander::MacroExpander(Lexer* lexer, - MacroSet* macroSet, - Diagnostics* diagnostics) : - mLexer(lexer), - mMacroSet(macroSet), - mDiagnostics(diagnostics) +MacroExpander::MacroExpander(Lexer *lexer, + MacroSet *macroSet, + Diagnostics *diagnostics) + : mLexer(lexer), + mMacroSet(macroSet), + mDiagnostics(diagnostics) { } @@ -63,7 +63,7 @@ MacroExpander::~MacroExpander() } } -void MacroExpander::lex(Token* token) +void MacroExpander::lex(Token *token) { while (true) { @@ -97,7 +97,7 @@ void MacroExpander::lex(Token* token) } } -void MacroExpander::getToken(Token* token) +void MacroExpander::getToken(Token *token) { if (mReserveToken.get()) { @@ -122,11 +122,11 @@ void MacroExpander::getToken(Token* token) } } -void MacroExpander::ungetToken(const Token& token) +void MacroExpander::ungetToken(const Token &token) { if (!mContextStack.empty()) { - MacroContext* context = mContextStack.back(); + MacroContext *context = mContextStack.back(); context->unget(); assert(context->replacements[context->index] == token); } @@ -148,7 +148,7 @@ bool MacroExpander::isNextTokenLeftParen() return lparen; } -bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier) +bool MacroExpander::pushMacro(const Macro ¯o, const Token &identifier) { assert(!macro.disabled); assert(!identifier.expansionDisabled()); @@ -162,7 +162,7 @@ bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier) // Macro is disabled for expansion until it is popped off the stack. macro.disabled = true; - MacroContext* context = new MacroContext; + MacroContext *context = new MacroContext; context->macro = ¯o; context->replacements.swap(replacements); mContextStack.push_back(context); @@ -173,7 +173,7 @@ void MacroExpander::popMacro() { assert(!mContextStack.empty()); - MacroContext* context = mContextStack.back(); + MacroContext *context = mContextStack.back(); mContextStack.pop_back(); assert(context->empty()); @@ -182,9 +182,9 @@ void MacroExpander::popMacro() delete context; } -bool MacroExpander::expandMacro(const Macro& macro, - const Token& identifier, - std::vector* replacements) +bool MacroExpander::expandMacro(const Macro ¯o, + const Token &identifier, + std::vector *replacements) { replacements->clear(); if (macro.type == Macro::kTypeObj) @@ -239,9 +239,9 @@ bool MacroExpander::expandMacro(const Macro& macro, return true; } -bool MacroExpander::collectMacroArgs(const Macro& macro, - const Token& identifier, - std::vector* args) +bool MacroExpander::collectMacroArgs(const Macro ¯o, + const Token &identifier, + std::vector *args) { Token token; getToken(&token); @@ -276,7 +276,8 @@ bool MacroExpander::collectMacroArgs(const Macro& macro, // The individual arguments are separated by comma tokens, but // the comma tokens between matching inner parentheses do not // seperate arguments. - if (openParens == 1) args->push_back(MacroArg()); + if (openParens == 1) + args->push_back(MacroArg()); isArg = openParens != 1; break; default: @@ -285,14 +286,15 @@ bool MacroExpander::collectMacroArgs(const Macro& macro, } if (isArg) { - MacroArg& arg = args->back(); + MacroArg &arg = args->back(); // Initial whitespace is not part of the argument. - if (arg.empty()) token.setHasLeadingSpace(false); + if (arg.empty()) + token.setHasLeadingSpace(false); arg.push_back(token); } } - const Macro::Parameters& params = macro.parameters; + const Macro::Parameters ¶ms = macro.parameters; // If there is only one empty argument, it is equivalent to no argument. if (params.empty() && (args->size() == 1) && args->front().empty()) { @@ -313,7 +315,7 @@ bool MacroExpander::collectMacroArgs(const Macro& macro, // inserted into the macro body. for (std::size_t i = 0; i < args->size(); ++i) { - MacroArg& arg = args->at(i); + MacroArg &arg = args->at(i); TokenLexer lexer(&arg); MacroExpander expander(&lexer, mMacroSet, mDiagnostics); @@ -328,13 +330,13 @@ bool MacroExpander::collectMacroArgs(const Macro& macro, return true; } -void MacroExpander::replaceMacroParams(const Macro& macro, - const std::vector& args, - std::vector* replacements) +void MacroExpander::replaceMacroParams(const Macro ¯o, + const std::vector &args, + std::vector *replacements) { for (std::size_t i = 0; i < macro.replacements.size(); ++i) { - const Token& repl = macro.replacements[i]; + const Token &repl = macro.replacements[i]; if (repl.type != Token::IDENTIFIER) { replacements->push_back(repl); @@ -353,7 +355,7 @@ void MacroExpander::replaceMacroParams(const Macro& macro, } std::size_t iArg = std::distance(macro.parameters.begin(), iter); - const MacroArg& arg = args[iArg]; + const MacroArg &arg = args[iArg]; if (arg.empty()) { continue; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h index 21b67571f1..d4fd091786 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h @@ -23,51 +23,65 @@ class Diagnostics; class MacroExpander : public Lexer { public: - MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics); + MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics); virtual ~MacroExpander(); - virtual void lex(Token* token); + virtual void lex(Token *token); private: PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander); - void getToken(Token* token); - void ungetToken(const Token& token); + void getToken(Token *token); + void ungetToken(const Token &token); bool isNextTokenLeftParen(); - bool pushMacro(const Macro& macro, const Token& identifier); + bool pushMacro(const Macro ¯o, const Token &identifier); void popMacro(); - bool expandMacro(const Macro& macro, - const Token& identifier, - std::vector* replacements); + bool expandMacro(const Macro ¯o, + const Token &identifier, + std::vector *replacements); typedef std::vector MacroArg; - bool collectMacroArgs(const Macro& macro, - const Token& identifier, - std::vector* args); - void replaceMacroParams(const Macro& macro, - const std::vector& args, - std::vector* replacements); + bool collectMacroArgs(const Macro ¯o, + const Token &identifier, + std::vector *args); + void replaceMacroParams(const Macro ¯o, + const std::vector &args, + std::vector *replacements); struct MacroContext { - const Macro* macro; + const Macro *macro; std::size_t index; std::vector replacements; - MacroContext() : macro(0), index(0) { } - bool empty() const { return index == replacements.size(); } - const Token& get() { return replacements[index++]; } - void unget() { assert(index > 0); --index; } + MacroContext() + : macro(0), + index(0) + { + } + bool empty() const + { + return index == replacements.size(); + } + const Token &get() + { + return replacements[index++]; + } + void unget() + { + assert(index > 0); + --index; + } }; - Lexer* mLexer; - MacroSet* mMacroSet; - Diagnostics* mDiagnostics; + Lexer *mLexer; + MacroSet *mMacroSet; + Diagnostics *mDiagnostics; std::auto_ptr mReserveToken; - std::vector mContextStack; + std::vector mContextStack; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp index 580ffba459..3522fa1abb 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp @@ -21,24 +21,24 @@ namespace pp struct PreprocessorImpl { - Diagnostics* diagnostics; + Diagnostics *diagnostics; MacroSet macroSet; Tokenizer tokenizer; DirectiveParser directiveParser; MacroExpander macroExpander; - PreprocessorImpl(Diagnostics* diag, - DirectiveHandler* directiveHandler) : - diagnostics(diag), - tokenizer(diag), - directiveParser(&tokenizer, ¯oSet, diag, directiveHandler), - macroExpander(&directiveParser, ¯oSet, diag) + PreprocessorImpl(Diagnostics *diag, + DirectiveHandler *directiveHandler) + : diagnostics(diag), + tokenizer(diag), + directiveParser(&tokenizer, ¯oSet, diag, directiveHandler), + macroExpander(&directiveParser, ¯oSet, diag) { } }; -Preprocessor::Preprocessor(Diagnostics* diagnostics, - DirectiveHandler* directiveHandler) +Preprocessor::Preprocessor(Diagnostics *diagnostics, + DirectiveHandler *directiveHandler) { mImpl = new PreprocessorImpl(diagnostics, directiveHandler); } @@ -49,7 +49,7 @@ Preprocessor::~Preprocessor() } bool Preprocessor::init(size_t count, - const char* const string[], + const char * const string[], const int length[]) { static const int kGLSLVersion = 100; @@ -63,7 +63,7 @@ bool Preprocessor::init(size_t count, return mImpl->tokenizer.init(count, string, length); } -void Preprocessor::predefineMacro(const char* name, int value) +void Preprocessor::predefineMacro(const char *name, int value) { std::ostringstream stream; stream << value; @@ -81,12 +81,7 @@ void Preprocessor::predefineMacro(const char* name, int value) mImpl->macroSet[name] = macro; } -void Preprocessor::setMaxTokenLength(size_t maxLength) -{ - mImpl->tokenizer.setMaxTokenLength(maxLength); -} - -void Preprocessor::lex(Token* token) +void Preprocessor::lex(Token *token) { bool validToken = false; while (!validToken) @@ -115,5 +110,9 @@ void Preprocessor::lex(Token* token) } } -} // namespace pp +void Preprocessor::setMaxTokenSize(size_t maxTokenSize) +{ + mImpl->tokenizer.setMaxTokenSize(maxTokenSize); +} +} // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h index 9a90d79a1a..0a55f1c9c1 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h @@ -22,7 +22,7 @@ struct Token; class Preprocessor { public: - Preprocessor(Diagnostics* diagnostics, DirectiveHandler* directiveHandler); + Preprocessor(Diagnostics *diagnostics, DirectiveHandler *directiveHandler); ~Preprocessor(); // count: specifies the number of elements in the string and length arrays. @@ -34,22 +34,19 @@ class Preprocessor // Each element in the length array may contain the length of the // corresponding string or a value less than 0 to indicate that the string // is null terminated. - bool init(size_t count, const char* const string[], const int length[]); + bool init(size_t count, const char * const string[], const int length[]); // Adds a pre-defined macro. - void predefineMacro(const char* name, int value); - // Sets maximum allowed token length. - // If token length exceeds this limit, - // the token text will be truncated to the given maximum length, and - // TOKEN_TOO_LONG diagnostic will be generated. - // The maximum length defaults to 256. - void setMaxTokenLength(size_t maxLength); + void predefineMacro(const char *name, int value); - void lex(Token* token); + void lex(Token *token); + + // Set maximum preprocessor token size + void setMaxTokenSize(size_t maxTokenSize); private: PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor); - PreprocessorImpl* mImpl; + PreprocessorImpl *mImpl; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h index 6982613ac7..d4c1a5e178 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h @@ -12,10 +12,18 @@ namespace pp struct SourceLocation { - SourceLocation() : file(0), line(0) { } - SourceLocation(int f, int l) : file(f), line(l) { } + SourceLocation() + : file(0), + line(0) + { + } + SourceLocation(int f, int l) + : file(f), + line(l) + { + } - bool equals(const SourceLocation& other) const + bool equals(const SourceLocation &other) const { return (file == other.file) && (line == other.line); } @@ -24,12 +32,12 @@ struct SourceLocation int line; }; -inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs) +inline bool operator==(const SourceLocation &lhs, const SourceLocation &rhs) { return lhs.equals(rhs); } -inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs) +inline bool operator!=(const SourceLocation &lhs, const SourceLocation &rhs) { return !lhs.equals(rhs); } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp index 67f50aa32c..d102654747 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp @@ -21,7 +21,7 @@ void Token::reset() text.clear(); } -bool Token::equals(const Token& other) const +bool Token::equals(const Token &other) const { return (type == other.type) && (flags == other.flags) && @@ -53,25 +53,25 @@ void Token::setExpansionDisabled(bool disable) flags &= ~EXPANSION_DISABLED; } -bool Token::iValue(int* value) const +bool Token::iValue(int *value) const { assert(type == CONST_INT); return numeric_lex_int(text, value); } -bool Token::uValue(unsigned int* value) const +bool Token::uValue(unsigned int *value) const { assert(type == CONST_INT); return numeric_lex_int(text, value); } -bool Token::fValue(float* value) const +bool Token::fValue(float *value) const { assert(type == CONST_FLOAT); return numeric_lex_float(text, value); } -std::ostream& operator<<(std::ostream& out, const Token& token) +std::ostream &operator<<(std::ostream &out, const Token &token) { if (token.hasLeadingSpace()) out << " "; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Token.h b/src/3rdparty/angle/src/compiler/preprocessor/Token.h index 8b553aecb6..8832e279c7 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Token.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Token.h @@ -62,27 +62,40 @@ struct Token EXPANSION_DISABLED = 1 << 2 }; - Token() : type(0), flags(0) { } + Token() + : type(0), + flags(0) + { + } void reset(); - bool equals(const Token& other) const; + bool equals(const Token &other) const; // Returns true if this is the first token on line. // It disregards any leading whitespace. - bool atStartOfLine() const { return (flags & AT_START_OF_LINE) != 0; } + bool atStartOfLine() const + { + return (flags & AT_START_OF_LINE) != 0; + } void setAtStartOfLine(bool start); - bool hasLeadingSpace() const { return (flags & HAS_LEADING_SPACE) != 0; } + bool hasLeadingSpace() const + { + return (flags & HAS_LEADING_SPACE) != 0; + } void setHasLeadingSpace(bool space); - bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; } + bool expansionDisabled() const + { + return (flags & EXPANSION_DISABLED) != 0; + } void setExpansionDisabled(bool disable); // Converts text into numeric value for CONST_INT and CONST_FLOAT token. // Returns false if the parsed value cannot fit into an int or float. - bool iValue(int* value) const; - bool uValue(unsigned int* value) const; - bool fValue(float* value) const; + bool iValue(int *value) const; + bool uValue(unsigned int *value) const; + bool fValue(float *value) const; int type; unsigned int flags; @@ -90,17 +103,17 @@ struct Token std::string text; }; -inline bool operator==(const Token& lhs, const Token& rhs) +inline bool operator==(const Token &lhs, const Token &rhs) { return lhs.equals(rhs); } -inline bool operator!=(const Token& lhs, const Token& rhs) +inline bool operator!=(const Token &lhs, const Token &rhs) { return !lhs.equals(rhs); } -extern std::ostream& operator<<(std::ostream& out, const Token& token); +extern std::ostream &operator<<(std::ostream &out, const Token &token); } // namepsace pp #endif // COMPILER_PREPROCESSOR_TOKEN_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h index 9d131f865a..07ad93da05 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 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. // @@ -21,7 +21,7 @@ class Tokenizer : public Lexer public: struct Context { - Diagnostics* diagnostics; + Diagnostics *diagnostics; Input input; // The location where yytext points to. Token location should track @@ -33,25 +33,25 @@ class Tokenizer : public Lexer bool lineStart; }; - Tokenizer(Diagnostics* diagnostics); + Tokenizer(Diagnostics *diagnostics); ~Tokenizer(); - bool init(size_t count, const char* const string[], const int length[]); + bool init(size_t count, const char * const string[], const int length[]); - void setMaxTokenLength(size_t maxLength) { mMaxTokenLength = maxLength; } void setFileNumber(int file); void setLineNumber(int line); + void setMaxTokenSize(size_t maxTokenSize); - virtual void lex(Token* token); + virtual void lex(Token *token); private: PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer); bool initScanner(); void destroyScanner(); - void* mHandle; // Scanner handle. + void *mHandle; // Scanner handle. Context mContext; // Scanner extra. - size_t mMaxTokenLength; + size_t mMaxTokenSize; // Maximum token size }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l index f1380b26b7..2a77b905a4 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l @@ -1,6 +1,6 @@ /* // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -14,7 +14,7 @@ IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh. %top{ // -// Copyright (c) 2011-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2011-2014 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. // @@ -78,9 +78,9 @@ NEWLINE \n|\r|\r\n IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]* PUNCTUATOR [][<>(){}.+-/*%^|&~=!:;,?] -DECIMAL_CONSTANT [1-9][0-9]* -OCTAL_CONSTANT 0[0-7]* -HEXADECIMAL_CONSTANT 0[xX][0-9a-fA-F]+ +DECIMAL_CONSTANT [1-9][0-9]*[uU]? +OCTAL_CONSTANT 0[0-7]*[uU]? +HEXADECIMAL_CONSTANT 0[xX][0-9a-fA-F]+[uU]? DIGIT [0-9] EXPONENT_PART [eE][+-]?{DIGIT}+ @@ -114,12 +114,12 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") return pp::Token::IDENTIFIER; } -{DECIMAL_CONSTANT}|{OCTAL_CONSTANT}|{HEXADECIMAL_CONSTANT} { +({DECIMAL_CONSTANT}[uU]?)|({OCTAL_CONSTANT}[uU]?)|({HEXADECIMAL_CONSTANT}[uU]?) { yylval->assign(yytext, yyleng); return pp::Token::CONST_INT; } -({DIGIT}+{EXPONENT_PART})|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?) { +({DIGIT}+{EXPONENT_PART}[fF]?)|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?[fF]?) { yylval->assign(yytext, yyleng); return pp::Token::CONST_FLOAT; } @@ -267,9 +267,7 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") namespace pp { -Tokenizer::Tokenizer(Diagnostics* diagnostics) - : mHandle(0), - mMaxTokenLength(256) +Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(0) { mContext.diagnostics = diagnostics; } @@ -279,9 +277,10 @@ Tokenizer::~Tokenizer() destroyScanner(); } -bool Tokenizer::init(size_t count, const char* const string[], const int length[]) +bool Tokenizer::init(size_t count, const char * const string[], const int length[]) { - if ((count > 0) && (string == 0)) return false; + if ((count > 0) && (string == 0)) + return false; mContext.input = Input(count, string, length); return initScanner(); @@ -299,14 +298,19 @@ void Tokenizer::setLineNumber(int line) yyset_lineno(line, mHandle); } -void Tokenizer::lex(Token* token) +void Tokenizer::setMaxTokenSize(size_t maxTokenSize) +{ + mMaxTokenSize = maxTokenSize; +} + +void Tokenizer::lex(Token *token) { token->type = yylex(&token->text, &token->location, mHandle); - if (token->text.size() > mMaxTokenLength) + if (token->text.size() > mMaxTokenSize) { mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG, token->location, token->text); - token->text.erase(mMaxTokenLength); + token->text.erase(mMaxTokenSize); } token->flags = 0; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/length_limits.h b/src/3rdparty/angle/src/compiler/preprocessor/length_limits.h deleted file mode 100644 index 4f1f71319f..0000000000 --- a/src/3rdparty/angle/src/compiler/preprocessor/length_limits.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) 2011 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. -// - -// -// length_limits.h -// - -#if !defined(__LENGTH_LIMITS_H) -#define __LENGTH_LIMITS_H 1 - -// These constants are factored out from the rest of the headers to -// make it easier to reference them from the compiler sources. - -// These lengths do not include the NULL terminator. -#define MAX_SYMBOL_NAME_LEN 256 -#define MAX_STRING_LEN 511 - -#endif // !(defined(__LENGTH_LIMITS_H) diff --git a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h index b04125d230..8a24540696 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h @@ -13,7 +13,7 @@ namespace pp { -inline std::ios::fmtflags numeric_base_int(const std::string& str) +inline std::ios::fmtflags numeric_base_int(const std::string &str) { if ((str.size() >= 2) && (str[0] == '0') && @@ -21,7 +21,7 @@ inline std::ios::fmtflags numeric_base_int(const std::string& str) { return std::ios::hex; } - else if ((str.size() >= 1) && (str[0] == '0')) + if ((str.size() >= 1) && (str[0] == '0')) { return std::ios::oct; } @@ -34,7 +34,7 @@ inline std::ios::fmtflags numeric_base_int(const std::string& str) // in which case false is returned. template -bool numeric_lex_int(const std::string& str, IntType* value) +bool numeric_lex_int(const std::string &str, IntType *value) { std::istringstream stream(str); // This should not be necessary, but MSVS has a buggy implementation. @@ -46,7 +46,7 @@ bool numeric_lex_int(const std::string& str, IntType* value) } template -bool numeric_lex_float(const std::string& str, FloatType* value) +bool numeric_lex_float(const std::string &str, FloatType *value) { std::istringstream stream(str); // Force "C" locale so that decimal character is always '.', and diff --git a/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h b/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h index 17164ea8b0..9fba9385c5 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h @@ -12,7 +12,7 @@ // A macro to disallow the copy constructor and operator= functions // This must be used in the private: declarations for a class. #define PP_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) + TypeName(const TypeName &); \ + void operator=(const TypeName &) #endif // COMPILER_PREPROCESSOR_PPUTILS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BaseTypes.h b/src/3rdparty/angle/src/compiler/translator/BaseTypes.h index 7bdaf14983..ba9ef5e609 100644 --- a/src/3rdparty/angle/src/compiler/translator/BaseTypes.h +++ b/src/3rdparty/angle/src/compiler/translator/BaseTypes.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -7,6 +7,8 @@ #ifndef _BASICTYPES_INCLUDED_ #define _BASICTYPES_INCLUDED_ +#include + // // Precision qualifiers // @@ -38,14 +40,34 @@ enum TBasicType EbtVoid, EbtFloat, EbtInt, + EbtUInt, EbtBool, - EbtGuardSamplerBegin, // non type: see implementation of IsSampler() + EbtGVec4, // non type: represents vec4, ivec4 and uvec4 + EbtGuardSamplerBegin, // non type: see implementation of IsSampler() EbtSampler2D, + EbtSampler3D, EbtSamplerCube, + EbtSampler2DArray, EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists. EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists. - EbtGuardSamplerEnd, // non type: see implementation of IsSampler() + EbtISampler2D, + EbtISampler3D, + EbtISamplerCube, + EbtISampler2DArray, + EbtUSampler2D, + EbtUSampler3D, + EbtUSamplerCube, + EbtUSampler2DArray, + EbtSampler2DShadow, + EbtSamplerCubeShadow, + EbtSampler2DArrayShadow, + EbtGuardSamplerEnd, // non type: see implementation of IsSampler() + EbtGSampler2D, // non type: represents sampler2D, isampler2D and usampler2D + EbtGSampler3D, // non type: represents sampler3D, isampler3D and usampler3D + EbtGSamplerCube, // non type: represents samplerCube, isamplerCube and usamplerCube + EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray and usampler2DArray EbtStruct, + EbtInterfaceBlock, EbtAddress, // should be deprecated?? EbtInvariant // used as a type when qualifying a previously declared variable as being invariant }; @@ -54,16 +76,31 @@ inline const char* getBasicString(TBasicType t) { switch (t) { - case EbtVoid: return "void"; break; - case EbtFloat: return "float"; break; - case EbtInt: return "int"; break; - case EbtBool: return "bool"; break; - case EbtSampler2D: return "sampler2D"; break; - case EbtSamplerCube: return "samplerCube"; break; - case EbtSamplerExternalOES: return "samplerExternalOES"; break; - case EbtSampler2DRect: return "sampler2DRect"; break; - case EbtStruct: return "structure"; break; - default: return "unknown type"; + case EbtVoid: return "void"; break; + case EbtFloat: return "float"; break; + case EbtInt: return "int"; break; + case EbtUInt: return "uint"; break; + case EbtBool: return "bool"; break; + case EbtSampler2D: return "sampler2D"; break; + case EbtSampler3D: return "sampler3D"; break; + case EbtSamplerCube: return "samplerCube"; break; + case EbtSamplerExternalOES: return "samplerExternalOES"; break; + case EbtSampler2DRect: return "sampler2DRect"; break; + case EbtSampler2DArray: return "sampler2DArray"; break; + case EbtISampler2D: return "isampler2D"; break; + case EbtISampler3D: return "isampler3D"; break; + case EbtISamplerCube: return "isamplerCube"; break; + case EbtISampler2DArray: return "isampler2DArray"; break; + case EbtUSampler2D: return "usampler2D"; break; + case EbtUSampler3D: return "usampler3D"; break; + case EbtUSamplerCube: return "usamplerCube"; break; + case EbtUSampler2DArray: return "usampler2DArray"; break; + case EbtSampler2DShadow: return "sampler2DShadow"; break; + case EbtSamplerCubeShadow: return "samplerCubeShadow"; break; + case EbtSampler2DArrayShadow: return "sampler2DArrayShadow"; break; + case EbtStruct: return "structure"; break; + case EbtInterfaceBlock: return "interface block"; break; + default: return "unknown type"; } } @@ -72,6 +109,191 @@ inline bool IsSampler(TBasicType type) return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd; } +inline bool IsIntegerSampler(TBasicType type) +{ + switch (type) + { + case EbtISampler2D: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + return true; + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSampler2D(TBasicType type) +{ + switch (type) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DRect: + case EbtSamplerExternalOES: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + return true; + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCube: + case EbtSamplerCubeShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSamplerCube(TBasicType type) +{ + switch (type) + { + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + return true; + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerExternalOES: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtISampler2D: + case EbtISampler3D: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSampler3D(TBasicType type) +{ + switch (type) + { + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + return true; + case EbtSampler2D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtISampler2D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSamplerArray(TBasicType type) +{ + switch (type) + { + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DArrayShadow: + return true; + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DRect: + case EbtSamplerExternalOES: + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCube: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsShadowSampler(TBasicType type) +{ + switch (type) + { + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return true; + case EbtISampler2D: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSampler2DRect: + case EbtSampler2DArray: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool SupportsPrecision(TBasicType type) +{ + return type == EbtFloat || type == EbtInt || type == EbtUInt || IsSampler(type); +} + // // Qualifiers and built-ins. These are mainly used to see what can be read // or written, and by the machine dependent translator to know which registers @@ -91,6 +313,11 @@ enum TQualifier EvqInvariantVaryingOut, // vertex shaders only read/write EvqUniform, // Readonly, vertex and fragment + EvqVertexIn, // Vertex shader input + EvqFragmentOut, // Fragment shader output + EvqVertexOut, // Vertex shader output + EvqFragmentIn, // Fragment shader input + // parameters EvqIn, EvqOut, @@ -111,10 +338,58 @@ enum TQualifier EvqFragData, EvqFragDepth, + // GLSL ES 3.0 vertex output and fragment input + EvqSmooth, // Incomplete qualifier, smooth is the default + EvqFlat, // Incomplete qualifier + EvqSmoothOut = EvqSmooth, + EvqFlatOut = EvqFlat, + EvqCentroidOut, // Implies smooth + EvqSmoothIn, + EvqFlatIn, + EvqCentroidIn, // Implies smooth + // end of list EvqLast }; +enum TLayoutMatrixPacking +{ + EmpUnspecified, + EmpRowMajor, + EmpColumnMajor +}; + +enum TLayoutBlockStorage +{ + EbsUnspecified, + EbsShared, + EbsPacked, + EbsStd140 +}; + +struct TLayoutQualifier +{ + int location; + TLayoutMatrixPacking matrixPacking; + TLayoutBlockStorage blockStorage; + + static TLayoutQualifier create() + { + TLayoutQualifier layoutQualifier; + + layoutQualifier.location = -1; + layoutQualifier.matrixPacking = EmpUnspecified; + layoutQualifier.blockStorage = EbsUnspecified; + + return layoutQualifier; + } + + bool isEmpty() const + { + return location == -1 && matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified; + } +}; + // // This is just for debug print out, carried along with the definitions above. // @@ -132,6 +407,10 @@ inline const char* getQualifierString(TQualifier q) case EvqInvariantVaryingIn: return "invariant varying"; break; case EvqInvariantVaryingOut:return "invariant varying"; break; case EvqUniform: return "uniform"; break; + case EvqVertexIn: return "in"; break; + case EvqFragmentOut: return "out"; break; + case EvqVertexOut: return "out"; break; + case EvqFragmentIn: return "in"; break; case EvqIn: return "in"; break; case EvqOut: return "out"; break; case EvqInOut: return "inout"; break; @@ -140,10 +419,53 @@ inline const char* getQualifierString(TQualifier q) case EvqFragCoord: return "FragCoord"; break; case EvqFrontFacing: return "FrontFacing"; break; case EvqFragColor: return "FragColor"; break; - case EvqFragData: return "FragData"; break; - case EvqFragDepth: return "FragDepth"; break; + case EvqFragData: return "FragData"; break; + case EvqFragDepth: return "FragDepth"; break; + case EvqSmoothOut: return "smooth out"; break; + case EvqCentroidOut: return "centroid out"; break; + case EvqFlatOut: return "flat out"; break; + case EvqSmoothIn: return "smooth in"; break; + case EvqCentroidIn: return "centroid in"; break; + case EvqFlatIn: return "flat in"; break; default: return "unknown qualifier"; } } +inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq) +{ + switch (mpq) + { + case EmpUnspecified: return "mp_unspecified"; + case EmpRowMajor: return "row_major"; + case EmpColumnMajor: return "column_major"; + default: return "unknown matrix packing"; + } +} + +inline const char* getBlockStorageString(TLayoutBlockStorage bsq) +{ + switch (bsq) + { + case EbsUnspecified: return "bs_unspecified"; + case EbsShared: return "shared"; + case EbsPacked: return "packed"; + case EbsStd140: return "std140"; + default: return "unknown block storage"; + } +} + +inline const char* getInterpolationString(TQualifier q) +{ + switch(q) + { + case EvqSmoothOut: return "smooth"; break; + case EvqCentroidOut: return "centroid"; break; + case EvqFlatOut: return "flat"; break; + case EvqSmoothIn: return "smooth"; break; + case EvqCentroidIn: return "centroid"; break; + case EvqFlatIn: return "flat"; break; + default: return "unknown interpolation"; + } +} + #endif // _BASICTYPES_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp index 92b71c6bdb..0e8239cc1e 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp @@ -4,8 +4,8 @@ // found in the LICENSE file. // +#include "angle_gl.h" #include "compiler/translator/BuiltInFunctionEmulator.h" - #include "compiler/translator/SymbolTable.h" namespace { @@ -243,7 +243,7 @@ public: default: return true; }; - const TIntermSequence& sequence = node->getSequence(); + const TIntermSequence& sequence = *(node->getSequence()); // Right now we only handle built-in functions with two parameters. if (sequence.size() != 2) return true; @@ -265,9 +265,9 @@ private: } // anonymous namepsace -BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType) +BuiltInFunctionEmulator::BuiltInFunctionEmulator(sh::GLenum shaderType) { - if (shaderType == SH_FRAGMENT_SHADER) { + if (shaderType == GL_FRAGMENT_SHADER) { mFunctionMask = kFunctionEmulationFragmentMask; mFunctionSource = kFunctionEmulationFragmentSource; } else { @@ -327,7 +327,7 @@ BuiltInFunctionEmulator::TBuiltInFunction BuiltInFunctionEmulator::IdentifyFunction( TOperator op, const TType& param) { - if (param.getNominalSize() > 4) + if (param.getNominalSize() > 4 || param.getSecondarySize() > 4) return TFunctionUnknown; unsigned int function = TFunctionUnknown; switch (op) { @@ -356,9 +356,9 @@ BuiltInFunctionEmulator::IdentifyFunction( { // Right now for all the emulated functions with two parameters, the two // parameters have the same type. - if (param1.isVector() != param2.isVector() || - param1.getNominalSize() != param2.getNominalSize() || - param1.getNominalSize() > 4) + if (param1.getNominalSize() != param2.getNominalSize() || + param1.getSecondarySize() != param2.getSecondarySize() || + param1.getNominalSize() > 4 || param1.getSecondarySize() > 4) return TFunctionUnknown; unsigned int function = TFunctionUnknown; diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h index cfb71a803a..926b6bed69 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h @@ -7,8 +7,6 @@ #ifndef COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ #define COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ -#include "GLSLANG/ShaderLang.h" - #include "compiler/translator/InfoSink.h" #include "compiler/translator/intermediate.h" @@ -19,7 +17,7 @@ // class BuiltInFunctionEmulator { public: - BuiltInFunctionEmulator(ShShaderType shaderType); + BuiltInFunctionEmulator(sh::GLenum shaderType); // Records that a function is called by the shader and might needs to be // emulated. If the function's group is not in mFunctionGroupFilter, this // becomes an no-op. diff --git a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp index 8f5d129104..71056f4297 100644 --- a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp +++ b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2013 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. // @@ -14,17 +14,17 @@ // a subclass of TCompiler. // TCompiler* ConstructCompiler( - ShShaderType type, ShShaderSpec spec, ShShaderOutput output) + sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) { switch (output) { - case SH_ESSL_OUTPUT: + case SH_ESSL_OUTPUT: return new TranslatorESSL(type, spec); - case SH_GLSL_OUTPUT: + case SH_GLSL_OUTPUT: return new TranslatorGLSL(type, spec); - case SH_HLSL9_OUTPUT: - case SH_HLSL11_OUTPUT: + case SH_HLSL9_OUTPUT: + case SH_HLSL11_OUTPUT: return new TranslatorHLSL(type, spec, output); - default: + default: return NULL; } } diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp index eb7465e35c..0606c72e39 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp @@ -1,33 +1,50 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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/BuiltInFunctionEmulator.h" +#include "compiler/translator/Compiler.h" #include "compiler/translator/DetectCallDepth.h" #include "compiler/translator/ForLoopUnroll.h" #include "compiler/translator/Initialize.h" #include "compiler/translator/InitializeParseContext.h" #include "compiler/translator/InitializeVariables.h" -#include "compiler/translator/MapLongVariableNames.h" #include "compiler/translator/ParseContext.h" #include "compiler/translator/RenameFunction.h" -#include "compiler/translator/ShHandle.h" +#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h" #include "compiler/translator/UnfoldShortCircuitAST.h" #include "compiler/translator/ValidateLimitations.h" +#include "compiler/translator/ValidateOutputs.h" #include "compiler/translator/VariablePacker.h" #include "compiler/translator/depgraph/DependencyGraph.h" #include "compiler/translator/depgraph/DependencyGraphOutput.h" #include "compiler/translator/timing/RestrictFragmentShaderTiming.h" #include "compiler/translator/timing/RestrictVertexShaderTiming.h" #include "third_party/compiler/ArrayBoundsClamper.h" +#include "angle_gl.h" +#include "common/utilities.h" -bool isWebGLBasedSpec(ShShaderSpec spec) +bool IsWebGLBasedSpec(ShShaderSpec spec) { return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC; } +size_t GetGlobalMaxTokenSize(ShShaderSpec spec) +{ + // WebGL defines a max token legnth of 256, while ES2 leaves max token + // size undefined. ES3 defines a max size of 1024 characters. + if (IsWebGLBasedSpec(spec)) + { + return 256; + } + else + { + return 1024; + } +} + namespace { class TScopedPoolAllocator { @@ -78,9 +95,10 @@ TShHandleBase::~TShHandleBase() allocator.popAll(); } -TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec) +TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) : shaderType(type), shaderSpec(spec), + outputType(output), maxUniformVectors(0), maxExpressionComplexity(0), maxCallStackDepth(0), @@ -88,18 +106,16 @@ TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec) clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), builtInFunctionEmulator(type) { - longNameMap = LongNameMap::GetInstance(); } TCompiler::~TCompiler() { - ASSERT(longNameMap); - longNameMap->Release(); } bool TCompiler::Init(const ShBuiltInResources& resources) { - maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ? + shaderVersion = 100; + maxUniformVectors = (shaderType == GL_VERTEX_SHADER) ? resources.MaxVertexUniformVectors : resources.MaxFragmentUniformVectors; maxExpressionComplexity = resources.MaxExpressionComplexity; @@ -132,7 +148,7 @@ bool TCompiler::compile(const char* const shaderStrings[], return true; // If compiling for WebGL, validate loop and indexing as well. - if (isWebGLBasedSpec(shaderSpec)) + if (IsWebGLBasedSpec(shaderSpec)) compileOptions |= SH_VALIDATE_LOOP_INDEXING; // First string is path of source file if flag is set. The actual source follows. @@ -159,14 +175,24 @@ bool TCompiler::compile(const char* const shaderStrings[], bool success = (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && (parseContext.treeRoot != NULL); + + shaderVersion = parseContext.getShaderVersion(); + if (success) { TIntermNode* root = parseContext.treeRoot; success = intermediate.postProcess(root); + // Disallow expressions deemed too complex. + if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) + success = limitExpressionComplexity(root); + if (success) success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0); + if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER) + success = validateOutputs(root); + if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) success = validateLimitations(root); @@ -178,7 +204,21 @@ bool TCompiler::compile(const char* const shaderStrings[], // Unroll for-loop markup needs to happen after validateLimitations pass. if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) - ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root); + { + ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex); + root->traverse(&marker); + } + if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX)) + { + ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex); + root->traverse(&marker); + if (marker.samplerArrayIndexIsFloatLoopIndex()) + { + infoSink.info.prefix(EPrefixError); + infoSink.info << "sampler array index is float loop index"; + success = false; + } + } // Built-in function emulation needs to happen after validateLimitations pass. if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) @@ -188,18 +228,7 @@ bool TCompiler::compile(const char* const shaderStrings[], if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); - // Disallow expressions deemed too complex. - if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) - success = limitExpressionComplexity(root); - - // Call mapLongVariableNames() before collectAttribsUniforms() so in - // collectAttribsUniforms() we already have the mapped symbol names and - // we could composite mapped and original variable names. - // Also, if we hash all the names, then no need to do this for long names. - if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL) - mapLongVariableNames(root); - - if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) + if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) initializeGLPosition(root); if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) @@ -221,11 +250,17 @@ bool TCompiler::compile(const char* const shaderStrings[], infoSink.info << "too many uniforms"; } } - if (success && shaderType == SH_VERTEX_SHADER && + if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE)) initializeVaryingsWithoutStaticUse(root); } + if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)) + { + ScalarizeVecAndMatConstructorArgs scalarizer; + root->traverse(&scalarizer); + } + if (success && (compileOptions & SH_INTERMEDIATE_TREE)) intermediate.outputTree(root); @@ -235,40 +270,43 @@ bool TCompiler::compile(const char* const shaderStrings[], // Cleanup memory. intermediate.remove(parseContext.treeRoot); - + SetGlobalParseContext(NULL); return success; } bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) { compileResources = resources; + setResourceString(); assert(symbolTable.isEmpty()); - symbolTable.push(); + symbolTable.push(); // COMMON_BUILTINS + symbolTable.push(); // ESSL1_BUILTINS + symbolTable.push(); // ESSL3_BUILTINS TPublicType integer; integer.type = EbtInt; - integer.size = 1; - integer.matrix = false; + integer.primarySize = 1; + integer.secondarySize = 1; integer.array = false; TPublicType floatingPoint; floatingPoint.type = EbtFloat; - floatingPoint.size = 1; - floatingPoint.matrix = false; + floatingPoint.primarySize = 1; + floatingPoint.secondarySize = 1; floatingPoint.array = false; TPublicType sampler; - sampler.size = 1; - sampler.matrix = false; + sampler.primarySize = 1; + sampler.secondarySize = 1; sampler.array = false; switch(shaderType) { - case SH_FRAGMENT_SHADER: + case GL_FRAGMENT_SHADER: symbolTable.setDefaultPrecision(integer, EbpMedium); break; - case SH_VERTEX_SHADER: + case GL_VERTEX_SHADER: symbolTable.setDefaultPrecision(integer, EbpHigh); symbolTable.setDefaultPrecision(floatingPoint, EbpHigh); break; @@ -291,6 +329,34 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) return true; } +void TCompiler::setResourceString() +{ + std::ostringstream strstream; + strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs + << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors + << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors + << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits + << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits + << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits + << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors + << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers + << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives + << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external + << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle + << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers + << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh + << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity + << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth + << ":EXT_frag_depth:" << compileResources.EXT_frag_depth + << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod + << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors + << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors + << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset + << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset; + + builtInResourcesString = strstream.str(); +} + void TCompiler::clearResults() { arrayBoundsClamper.Cleanup(); @@ -298,9 +364,13 @@ void TCompiler::clearResults() infoSink.obj.erase(); infoSink.debug.erase(); - attribs.clear(); + attributes.clear(); + outputVariables.clear(); uniforms.clear(); + expandedUniforms.clear(); varyings.clear(); + expandedVaryings.clear(); + interfaceBlocks.clear(); builtInFunctionEmulator.Cleanup(); @@ -333,6 +403,13 @@ bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool lim } } +bool TCompiler::validateOutputs(TIntermNode* root) +{ + ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers); + root->traverse(&validateOutputs); + return (validateOutputs.numErrors() == 0); +} + void TCompiler::rewriteCSSShader(TIntermNode* root) { RenameFunction renamer("main(", "css_main("); @@ -354,20 +431,20 @@ bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph) return false; } - if (shaderType == SH_FRAGMENT_SHADER) + if (shaderType == GL_FRAGMENT_SHADER) { TDependencyGraph graph(root); // Output any errors first. bool success = enforceFragmentShaderTimingRestrictions(graph); - + // Then, output the dependency graph. if (outputGraph) { TDependencyGraphOutput output(infoSink.info); output.outputAllSpanningTrees(graph); } - + return success; } else @@ -378,8 +455,15 @@ bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph) bool TCompiler::limitExpressionComplexity(TIntermNode* root) { - TIntermTraverser traverser; + TMaxDepthTraverser traverser(maxExpressionComplexity+1); root->traverse(&traverser); + + if (traverser.getMaxDepth() > maxExpressionComplexity) + { + infoSink.info << "Expression too complex."; + return false; + } + TDependencyGraph graph(root); for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls(); @@ -391,11 +475,6 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root) samplerSymbol->traverse(&graphTraverser); } - if (traverser.getMaxDepth() > maxExpressionComplexity) - { - infoSink.info << "Expression too complex."; - return false; - } return true; } @@ -415,14 +494,24 @@ bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root) void TCompiler::collectVariables(TIntermNode* root) { - CollectVariables collect(attribs, uniforms, varyings, hashFunction); + CollectVariables collect(&attributes, + &outputVariables, + &uniforms, + &varyings, + &interfaceBlocks, + hashFunction); root->traverse(&collect); + + // For backwards compatiblity with ShGetVariableInfo, expand struct + // uniforms and varyings into separate variables for each field. + ExpandVariables(uniforms, &expandedUniforms); + ExpandVariables(varyings, &expandedVaryings); } bool TCompiler::enforcePackingRestrictions() { VariablePacker packer; - return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms); + return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms); } void TCompiler::initializeGLPosition(TIntermNode* root) @@ -440,45 +529,16 @@ void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root) InitializeVariables::InitVariableInfoList variables; for (size_t ii = 0; ii < varyings.size(); ++ii) { - const TVariableInfo& varying = varyings[ii]; + const sh::Varying& varying = varyings[ii]; if (varying.staticUse) continue; - unsigned char size = 0; - bool matrix = false; - switch (varying.type) - { - case SH_FLOAT: - size = 1; - break; - case SH_FLOAT_VEC2: - size = 2; - break; - case SH_FLOAT_VEC3: - size = 3; - break; - case SH_FLOAT_VEC4: - size = 4; - break; - case SH_FLOAT_MAT2: - size = 2; - matrix = true; - break; - case SH_FLOAT_MAT3: - size = 3; - matrix = true; - break; - case SH_FLOAT_MAT4: - size = 4; - matrix = true; - break; - default: - ASSERT(false); - } - TType type(EbtFloat, EbpUndefined, EvqVaryingOut, size, matrix, varying.isArray); + unsigned char primarySize = static_cast(gl::VariableColumnCount(varying.type)); + unsigned char secondarySize = static_cast(gl::VariableRowCount(varying.type)); + TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray()); TString name = varying.name.c_str(); - if (varying.isArray) + if (varying.isArray()) { - type.setArraySize(varying.size); + type.setArraySize(varying.arraySize); name = name.substr(0, name.find_first_of('[')); } @@ -489,18 +549,6 @@ void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root) root->traverse(&initializer); } -void TCompiler::mapLongVariableNames(TIntermNode* root) -{ - ASSERT(longNameMap); - MapLongVariableNames map(longNameMap); - root->traverse(&map); -} - -int TCompiler::getMappedNameMaxLength() const -{ - return MAX_SHORTENED_IDENTIFIER_SIZE + 1; -} - const TExtensionBehavior& TCompiler::getExtensionBehavior() const { return extensionBehavior; diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.h b/src/3rdparty/angle/src/compiler/translator/Compiler.h new file mode 100644 index 0000000000..5eac2d89d1 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.h @@ -0,0 +1,191 @@ +// +// Copyright (c) 2002-2013 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. +// + +#ifndef _SHHANDLE_INCLUDED_ +#define _SHHANDLE_INCLUDED_ + +// +// Machine independent part of the compiler private objects +// sent as ShHandle to the driver. +// +// This should not be included by driver code. +// + +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/ExtensionBehavior.h" +#include "compiler/translator/HashNames.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/VariableInfo.h" +#include "third_party/compiler/ArrayBoundsClamper.h" + +class TCompiler; +class TDependencyGraph; +class TranslatorHLSL; + +// +// Helper function to identify specs that are based on the WebGL spec, +// like the CSS Shaders spec. +// +bool IsWebGLBasedSpec(ShShaderSpec spec); + +// +// The base class used to back handles returned to the driver. +// +class TShHandleBase { +public: + TShHandleBase(); + virtual ~TShHandleBase(); + virtual TCompiler* getAsCompiler() { return 0; } + virtual TranslatorHLSL* getAsTranslatorHLSL() { return 0; } + +protected: + // Memory allocator. Allocates and tracks memory required by the compiler. + // Deallocates all memory when compiler is destructed. + TPoolAllocator allocator; +}; + +// +// The base class for the machine dependent compiler to derive from +// for managing object code from the compile. +// +class TCompiler : public TShHandleBase +{ + public: + TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); + virtual ~TCompiler(); + virtual TCompiler* getAsCompiler() { return this; } + + bool Init(const ShBuiltInResources& resources); + bool compile(const char* const shaderStrings[], + size_t numStrings, + int compileOptions); + + // Get results of the last compilation. + int getShaderVersion() const { return shaderVersion; } + TInfoSink& getInfoSink() { return infoSink; } + + const std::vector &getAttributes() const { return attributes; } + const std::vector &getOutputVariables() const { return outputVariables; } + const std::vector &getUniforms() const { return uniforms; } + const std::vector &getExpandedUniforms() const { return expandedUniforms; } + const std::vector &getVaryings() const { return varyings; } + const std::vector &getExpandedVaryings() const { return expandedVaryings; } + const std::vector &getInterfaceBlocks() const { return interfaceBlocks; } + + ShHashFunction64 getHashFunction() const { return hashFunction; } + NameMap& getNameMap() { return nameMap; } + TSymbolTable& getSymbolTable() { return symbolTable; } + ShShaderSpec getShaderSpec() const { return shaderSpec; } + ShShaderOutput getOutputType() const { return outputType; } + std::string getBuiltInResourcesString() const { return builtInResourcesString; } + + protected: + sh::GLenum getShaderType() const { return shaderType; } + // Initialize symbol-table with built-in symbols. + bool InitBuiltInSymbolTable(const ShBuiltInResources& resources); + // Compute the string representation of the built-in resources + void setResourceString(); + // Clears the results from the previous compilation. + void clearResults(); + // Return true if function recursion is detected or call depth exceeded. + bool detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth); + // Returns true if a program has no conflicting or missing fragment outputs + bool validateOutputs(TIntermNode* root); + // Rewrites a shader's intermediate tree according to the CSS Shaders spec. + void rewriteCSSShader(TIntermNode* root); + // Returns true if the given shader does not exceed the minimum + // functionality mandated in GLSL 1.0 spec Appendix A. + bool validateLimitations(TIntermNode* root); + // Collect info for all attribs, uniforms, varyings. + void collectVariables(TIntermNode* root); + // Translate to object code. + virtual void translate(TIntermNode* root) = 0; + // Returns true if, after applying the packing rules in the GLSL 1.017 spec + // Appendix A, section 7, the shader does not use too many uniforms. + bool enforcePackingRestrictions(); + // Insert statements to initialize varyings without static use in the beginning + // of main(). It is to work around a Mac driver where such varyings in a vertex + // shader may be optimized out incorrectly at compile time, causing a link failure. + // This function should only be applied to vertex shaders. + void initializeVaryingsWithoutStaticUse(TIntermNode* root); + // Insert gl_Position = vec4(0,0,0,0) to the beginning of main(). + // It is to work around a Linux driver bug where missing this causes compile failure + // while spec says it is allowed. + // This function should only be applied to vertex shaders. + void initializeGLPosition(TIntermNode* root); + // Returns true if the shader passes the restrictions that aim to prevent timing attacks. + bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph); + // Returns true if the shader does not use samplers. + bool enforceVertexShaderTimingRestrictions(TIntermNode* root); + // Returns true if the shader does not use sampler dependent values to affect control + // flow or in operations whose time can depend on the input values. + bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph); + // Return true if the maximum expression complexity is below the limit. + bool limitExpressionComplexity(TIntermNode* root); + // Get built-in extensions with default behavior. + const TExtensionBehavior& getExtensionBehavior() const; + // Get the resources set by InitBuiltInSymbolTable + const ShBuiltInResources& getResources() const; + + const ArrayBoundsClamper& getArrayBoundsClamper() const; + ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const; + const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const; + + std::vector attributes; + std::vector outputVariables; + std::vector uniforms; + std::vector expandedUniforms; + std::vector varyings; + std::vector expandedVaryings; + std::vector interfaceBlocks; + + private: + sh::GLenum shaderType; + ShShaderSpec shaderSpec; + ShShaderOutput outputType; + + int maxUniformVectors; + int maxExpressionComplexity; + int maxCallStackDepth; + + ShBuiltInResources compileResources; + std::string builtInResourcesString; + + // Built-in symbol table for the given language, spec, and resources. + // It is preserved from compile-to-compile. + TSymbolTable symbolTable; + // Built-in extensions with default behavior. + TExtensionBehavior extensionBehavior; + bool fragmentPrecisionHigh; + + ArrayBoundsClamper arrayBoundsClamper; + ShArrayIndexClampingStrategy clampingStrategy; + BuiltInFunctionEmulator builtInFunctionEmulator; + + // Results of compilation. + int shaderVersion; + TInfoSink infoSink; // Output sink. + + // name hashing. + ShHashFunction64 hashFunction; + NameMap nameMap; +}; + +// +// This is the interface between the machine independent code +// and the machine dependent code. +// +// The machine dependent code should derive from the classes +// above. Then Construct*() and Delete*() will create and +// destroy the machine dependent objects, which contain the +// above machine independent information. +// +TCompiler* ConstructCompiler( + sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); +void DeleteCompiler(TCompiler*); + +#endif // _SHHANDLE_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h index b1e37885f9..5e86c64805 100644 --- a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h +++ b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -18,14 +18,74 @@ public: type = EbtVoid; } + bool cast(TBasicType newType, const ConstantUnion &constant) + { + switch (newType) + { + case EbtFloat: + switch (constant.type) + { + case EbtInt: setFConst(static_cast(constant.getIConst())); break; + case EbtUInt: setFConst(static_cast(constant.getUConst())); break; + case EbtBool: setFConst(static_cast(constant.getBConst())); break; + case EbtFloat: setFConst(static_cast(constant.getFConst())); break; + default: return false; + } + break; + case EbtInt: + switch (constant.type) + { + case EbtInt: setIConst(static_cast(constant.getIConst())); break; + case EbtUInt: setIConst(static_cast(constant.getUConst())); break; + case EbtBool: setIConst(static_cast(constant.getBConst())); break; + case EbtFloat: setIConst(static_cast(constant.getFConst())); break; + default: return false; + } + break; + case EbtUInt: + switch (constant.type) + { + case EbtInt: setUConst(static_cast(constant.getIConst())); break; + case EbtUInt: setUConst(static_cast(constant.getUConst())); break; + case EbtBool: setUConst(static_cast(constant.getBConst())); break; + case EbtFloat: setUConst(static_cast(constant.getFConst())); break; + default: return false; + } + break; + case EbtBool: + switch (constant.type) + { + case EbtInt: setBConst(constant.getIConst() != 0); break; + case EbtUInt: setBConst(constant.getUConst() != 0); break; + case EbtBool: setBConst(constant.getBConst()); break; + case EbtFloat: setBConst(constant.getFConst() != 0.0f); break; + default: return false; + } + break; + case EbtStruct: // Struct fields don't get cast + switch (constant.type) + { + case EbtInt: setIConst(constant.getIConst()); break; + case EbtUInt: setUConst(constant.getUConst()); break; + case EbtBool: setBConst(constant.getBConst()); break; + case EbtFloat: setFConst(constant.getFConst()); break; + default: return false; + } + break; + default: + return false; + } + + return true; + } + void setIConst(int i) {iConst = i; type = EbtInt; } + void setUConst(unsigned int u) { uConst = u; type = EbtUInt; } void setFConst(float f) {fConst = f; type = EbtFloat; } void setBConst(bool b) {bConst = b; type = EbtBool; } - int getIConst() { return iConst; } - float getFConst() { return fConst; } - bool getBConst() { return bConst; } int getIConst() const { return iConst; } + unsigned int getUConst() const { return uConst; } float getFConst() const { return fConst; } bool getBConst() const { return bConst; } @@ -34,6 +94,11 @@ public: return i == iConst; } + bool operator==(const unsigned int u) const + { + return u == uConst; + } + bool operator==(const float f) const { return f == fConst; @@ -52,6 +117,8 @@ public: switch (type) { case EbtInt: return constant.iConst == iConst; + case EbtUInt: + return constant.uConst == uConst; case EbtFloat: return constant.fConst == fConst; case EbtBool: @@ -66,6 +133,11 @@ public: return !operator==(i); } + bool operator!=(const unsigned int u) const + { + return !operator==(u); + } + bool operator!=(const float f) const { return !operator==(f); @@ -87,6 +159,8 @@ public: switch (type) { case EbtInt: return iConst > constant.iConst; + case EbtUInt: + return uConst > constant.uConst; case EbtFloat: return fConst > constant.fConst; default: @@ -100,6 +174,8 @@ public: switch (type) { case EbtInt: return iConst < constant.iConst; + case EbtUInt: + return uConst < constant.uConst; case EbtFloat: return fConst < constant.fConst; default: @@ -113,6 +189,7 @@ public: assert(type == constant.type); switch (type) { case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst + constant.uConst); break; case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break; default: assert(false && "Default missing"); } @@ -126,6 +203,7 @@ public: assert(type == constant.type); switch (type) { case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst - constant.uConst); break; case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break; default: assert(false && "Default missing"); } @@ -139,6 +217,7 @@ public: assert(type == constant.type); switch (type) { case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst * constant.uConst); break; case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break; default: assert(false && "Default missing"); } @@ -152,6 +231,7 @@ public: assert(type == constant.type); switch (type) { case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst % constant.uConst); break; default: assert(false && "Default missing"); } @@ -164,6 +244,7 @@ public: assert(type == constant.type); switch (type) { case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst >> constant.uConst); break; default: assert(false && "Default missing"); } @@ -176,6 +257,7 @@ public: assert(type == constant.type); switch (type) { case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst << constant.uConst); break; default: assert(false && "Default missing"); } @@ -188,6 +270,7 @@ public: assert(type == constant.type); switch (type) { case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst & constant.uConst); break; default: assert(false && "Default missing"); } @@ -200,6 +283,7 @@ public: assert(type == constant.type); switch (type) { case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst | constant.uConst); break; default: assert(false && "Default missing"); } @@ -212,6 +296,7 @@ public: assert(type == constant.type); switch (type) { case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst ^ constant.uConst); break; default: assert(false && "Default missing"); } @@ -247,6 +332,7 @@ private: union { int iConst; // used for ivec, scalar ints + unsigned int uConst; // used for uvec, scalar uints bool bConst; // used for bvec, scalar bools float fConst; // used for vec, mat, scalar floats } ; diff --git a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h index 5e7f23d15f..cb76f1de02 100644 --- a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h +++ b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h @@ -7,8 +7,6 @@ #ifndef COMPILER_DETECT_RECURSION_H_ #define COMPILER_DETECT_RECURSION_H_ -#include "GLSLANG/ShaderLang.h" - #include #include "compiler/translator/intermediate.h" #include "compiler/translator/VariableInfo.h" diff --git a/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp b/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp index 99506c0849..92db3e55cf 100644 --- a/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2013 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. // diff --git a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h index cb71bb1204..664da7803b 100644 --- a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h +++ b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2013 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. // diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp index 662c8ae624..59d2835f7b 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2013 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. // @@ -26,9 +26,11 @@ static TBehavior getBehavior(const std::string& str) } TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior, - TDiagnostics& diagnostics) + TDiagnostics& diagnostics, + int& shaderVersion) : mExtensionBehavior(extBehavior), - mDiagnostics(diagnostics) + mDiagnostics(diagnostics), + mShaderVersion(shaderVersion) { } @@ -148,9 +150,12 @@ void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc, int version) { - static const int kVersion = 100; - - if (version != kVersion) + if (version == 100 || + version == 300) + { + mShaderVersion = version; + } + else { std::stringstream stream; stream << version; diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h index eb5f055494..69418c277a 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h @@ -17,7 +17,8 @@ class TDirectiveHandler : public pp::DirectiveHandler { public: TDirectiveHandler(TExtensionBehavior& extBehavior, - TDiagnostics& diagnostics); + TDiagnostics& diagnostics, + int& shaderVersion); virtual ~TDirectiveHandler(); const TPragma& pragma() const { return mPragma; } @@ -41,6 +42,7 @@ class TDirectiveHandler : public pp::DirectiveHandler TPragma mPragma; TExtensionBehavior& mExtensionBehavior; TDiagnostics& mDiagnostics; + int& mShaderVersion; }; #endif // COMPILER_DIRECTIVE_HANDLER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.cpp b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.cpp new file mode 100644 index 0000000000..a751b768b7 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.cpp @@ -0,0 +1,77 @@ +// +// Copyright (c) 2013 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/FlagStd140Structs.h" + +namespace sh +{ + +bool FlagStd140Structs::visitBinary(Visit visit, TIntermBinary *binaryNode) +{ + if (binaryNode->getRight()->getBasicType() == EbtStruct) + { + switch (binaryNode->getOp()) + { + case EOpIndexDirectInterfaceBlock: + case EOpIndexDirectStruct: + if (isInStd140InterfaceBlock(binaryNode->getLeft())) + { + mFlaggedNodes.push_back(binaryNode); + } + break; + + default: break; + } + return false; + } + + if (binaryNode->getOp() == EOpIndexDirectStruct) + { + return false; + } + + return visit == PreVisit; +} + +void FlagStd140Structs::visitSymbol(TIntermSymbol *symbol) +{ + if (isInStd140InterfaceBlock(symbol) && symbol->getBasicType() == EbtStruct) + { + mFlaggedNodes.push_back(symbol); + } +} + +bool FlagStd140Structs::isInStd140InterfaceBlock(TIntermTyped *node) const +{ + TIntermBinary *binaryNode = node->getAsBinaryNode(); + + if (binaryNode) + { + return isInStd140InterfaceBlock(binaryNode->getLeft()); + } + + const TType &type = node->getType(); + + // determine if we are in the standard layout + const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); + if (interfaceBlock) + { + return (interfaceBlock->blockStorage() == EbsStd140); + } + + return false; +} + +std::vector FlagStd140ValueStructs(TIntermNode *node) +{ + FlagStd140Structs flaggingTraversal; + + node->traverse(&flaggingTraversal); + + return flaggingTraversal.getFlaggedNodes(); +} + +} diff --git a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h new file mode 100644 index 0000000000..610205eb92 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2013 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. +// + +#ifndef COMPILER_FLAGSTD140STRUCTS_H_ +#define COMPILER_FLAGSTD140STRUCTS_H_ + +#include "compiler/translator/intermediate.h" + +namespace sh +{ + +// This class finds references to nested structs of std140 blocks that access +// the nested struct "by value", where the padding added in the translator +// conflicts with the "natural" unpadded type. +class FlagStd140Structs : public TIntermTraverser +{ + public: + const std::vector getFlaggedNodes() const { return mFlaggedNodes; } + + protected: + virtual bool visitBinary(Visit visit, TIntermBinary *binaryNode); + virtual void visitSymbol(TIntermSymbol *symbol); + + private: + bool isInStd140InterfaceBlock(TIntermTyped *node) const; + + std::vector mFlaggedNodes; +}; + +std::vector FlagStd140ValueStructs(TIntermNode *node); + +} + +#endif // COMPILER_FLAGSTD140STRUCTS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp index 89e6f1a62b..f3be20d978 100644 --- a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp @@ -6,210 +6,77 @@ #include "compiler/translator/ForLoopUnroll.h" -namespace { - -class IntegerForLoopUnrollMarker : public TIntermTraverser { -public: - - virtual bool visitLoop(Visit, TIntermLoop* node) - { - // This is called after ValidateLimitations pass, so all the ASSERT - // should never fail. - // See ValidateLimitations::validateForLoopInit(). - ASSERT(node); - ASSERT(node->getType() == ELoopFor); - ASSERT(node->getInit()); - TIntermAggregate* decl = node->getInit()->getAsAggregate(); - ASSERT(decl && decl->getOp() == EOpDeclaration); - TIntermSequence& declSeq = decl->getSequence(); - ASSERT(declSeq.size() == 1); - TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); - ASSERT(declInit && declInit->getOp() == EOpInitialize); - ASSERT(declInit->getLeft()); - TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); - ASSERT(symbol); - TBasicType type = symbol->getBasicType(); - ASSERT(type == EbtInt || type == EbtFloat); - if (type == EbtInt) - node->setUnrollFlag(true); - return true; - } - -}; - -} // anonymous namepsace - -void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info) +bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node) { - ASSERT(node->getType() == ELoopFor); - ASSERT(node->getUnrollFlag()); - - TIntermNode* init = node->getInit(); - ASSERT(init != NULL); - TIntermAggregate* decl = init->getAsAggregate(); - ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration)); - TIntermSequence& declSeq = decl->getSequence(); - ASSERT(declSeq.size() == 1); - TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); - ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize)); - TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); - ASSERT(symbol != NULL); - ASSERT(symbol->getBasicType() == EbtInt); - - info.id = symbol->getId(); - - ASSERT(declInit->getRight() != NULL); - TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion(); - ASSERT(initNode != NULL); - - info.initValue = evaluateIntConstant(initNode); - info.currentValue = info.initValue; - - TIntermNode* cond = node->getCondition(); - ASSERT(cond != NULL); - TIntermBinary* binOp = cond->getAsBinaryNode(); - ASSERT(binOp != NULL); - ASSERT(binOp->getRight() != NULL); - ASSERT(binOp->getRight()->getAsConstantUnion() != NULL); - - info.incrementValue = getLoopIncrement(node); - info.stopValue = evaluateIntConstant( - binOp->getRight()->getAsConstantUnion()); - info.op = binOp->getOp(); -} - -void ForLoopUnroll::Step() -{ - ASSERT(mLoopIndexStack.size() > 0); - TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1]; - info.currentValue += info.incrementValue; -} + if (mUnrollCondition != kSamplerArrayIndex) + return true; -bool ForLoopUnroll::SatisfiesLoopCondition() -{ - ASSERT(mLoopIndexStack.size() > 0); - TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1]; - // Relational operator is one of: > >= < <= == or !=. - switch (info.op) { - case EOpEqual: - return (info.currentValue == info.stopValue); - case EOpNotEqual: - return (info.currentValue != info.stopValue); - case EOpLessThan: - return (info.currentValue < info.stopValue); - case EOpGreaterThan: - return (info.currentValue > info.stopValue); - case EOpLessThanEqual: - return (info.currentValue <= info.stopValue); - case EOpGreaterThanEqual: - return (info.currentValue >= info.stopValue); + // If a sampler array index is also the loop index, + // 1) if the index type is integer, mark the loop for unrolling; + // 2) if the index type if float, set a flag to later fail compile. + switch (node->getOp()) + { + case EOpIndexIndirect: + if (node->getLeft() != NULL && node->getRight() != NULL && node->getLeft()->getAsSymbolNode()) + { + TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode(); + if (IsSampler(symbol->getBasicType()) && symbol->isArray() && !mLoopStack.empty()) + { + mVisitSamplerArrayIndexNodeInsideLoop = true; + node->getRight()->traverse(this); + mVisitSamplerArrayIndexNodeInsideLoop = false; + // We have already visited all the children. + return false; + } + } + break; default: - UNREACHABLE(); + break; } - return false; + return true; } -bool ForLoopUnroll::NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol) +bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node) { - for (TVector::iterator i = mLoopIndexStack.begin(); - i != mLoopIndexStack.end(); - ++i) { - if (i->id == symbol->getId()) - return true; + if (mUnrollCondition == kIntegerIndex) + { + // Check if loop index type is integer. + // This is called after ValidateLimitations pass, so all the calls + // should be valid. See ValidateLimitations::validateForLoopInit(). + TIntermSequence *declSeq = node->getInit()->getAsAggregate()->getSequence(); + TIntermSymbol *symbol = (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode(); + if (symbol->getBasicType() == EbtInt) + node->setUnrollFlag(true); } - return false; -} -int ForLoopUnroll::GetLoopIndexValue(TIntermSymbol* symbol) -{ - for (TVector::iterator i = mLoopIndexStack.begin(); - i != mLoopIndexStack.end(); - ++i) { - if (i->id == symbol->getId()) - return i->currentValue; + TIntermNode *body = node->getBody(); + if (body != NULL) + { + mLoopStack.push(node); + body->traverse(this); + mLoopStack.pop(); } - UNREACHABLE(); + // The loop is fully processed - no need to visit children. return false; } -void ForLoopUnroll::Push(TLoopIndexInfo& info) -{ - mLoopIndexStack.push_back(info); -} - -void ForLoopUnroll::Pop() +void ForLoopUnrollMarker::visitSymbol(TIntermSymbol* symbol) { - mLoopIndexStack.pop_back(); -} - -// static -void ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling( - TIntermNode* root) -{ - ASSERT(root); - - IntegerForLoopUnrollMarker marker; - root->traverse(&marker); -} - -int ForLoopUnroll::getLoopIncrement(TIntermLoop* node) -{ - TIntermNode* expr = node->getExpression(); - ASSERT(expr != NULL); - // for expression has one of the following forms: - // loop_index++ - // loop_index-- - // loop_index += constant_expression - // loop_index -= constant_expression - // ++loop_index - // --loop_index - // The last two forms are not specified in the spec, but I am assuming - // its an oversight. - TIntermUnary* unOp = expr->getAsUnaryNode(); - TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode(); - - TOperator op = EOpNull; - TIntermConstantUnion* incrementNode = NULL; - if (unOp != NULL) { - op = unOp->getOp(); - } else if (binOp != NULL) { - op = binOp->getOp(); - ASSERT(binOp->getRight() != NULL); - incrementNode = binOp->getRight()->getAsConstantUnion(); - ASSERT(incrementNode != NULL); - } - - int increment = 0; - // The operator is one of: ++ -- += -=. - switch (op) { - case EOpPostIncrement: - case EOpPreIncrement: - ASSERT((unOp != NULL) && (binOp == NULL)); - increment = 1; - break; - case EOpPostDecrement: - case EOpPreDecrement: - ASSERT((unOp != NULL) && (binOp == NULL)); - increment = -1; - break; - case EOpAddAssign: - ASSERT((unOp == NULL) && (binOp != NULL)); - increment = evaluateIntConstant(incrementNode); + if (!mVisitSamplerArrayIndexNodeInsideLoop) + return; + TIntermLoop *loop = mLoopStack.findLoop(symbol); + if (loop) + { + switch (symbol->getBasicType()) + { + case EbtFloat: + mSamplerArrayIndexIsFloatLoopIndex = true; break; - case EOpSubAssign: - ASSERT((unOp == NULL) && (binOp != NULL)); - increment = - evaluateIntConstant(incrementNode); + case EbtInt: + loop->setUnrollFlag(true); break; - default: - ASSERT(false); + default: + UNREACHABLE(); + } } - - return increment; -} - -int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node) -{ - ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL)); - return node->getIConst(0); } - diff --git a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h index afd70d1fd2..a820d2a20d 100644 --- a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h +++ b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h @@ -7,46 +7,44 @@ #ifndef COMPILER_FORLOOPUNROLL_H_ #define COMPILER_FORLOOPUNROLL_H_ -#include "compiler/translator/intermediate.h" - -struct TLoopIndexInfo { - int id; - int initValue; - int stopValue; - int incrementValue; - TOperator op; - int currentValue; -}; - -class ForLoopUnroll { -public: - ForLoopUnroll() { } - - void FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info); - - // Update the info.currentValue for the next loop iteration. - void Step(); - - // Return false if loop condition is no longer satisfied. - bool SatisfiesLoopCondition(); - - // Check if the symbol is the index of a loop that's unrolled. - bool NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol); - - // Return the current value of a given loop index symbol. - int GetLoopIndexValue(TIntermSymbol* symbol); - - void Push(TLoopIndexInfo& info); - void Pop(); - - static void MarkForLoopsWithIntegerIndicesForUnrolling(TIntermNode* root); - -private: - int getLoopIncrement(TIntermLoop* node); - - int evaluateIntConstant(TIntermConstantUnion* node); - - TVector mLoopIndexStack; +#include "compiler/translator/LoopInfo.h" + +// This class detects for-loops that needs to be unrolled. +// Currently we support two unroll conditions: +// 1) kForLoopWithIntegerIndex: unroll if the index type is integer. +// 2) kForLoopWithSamplerArrayIndex: unroll where a sampler array index +// is also the loop integer index, and reject and fail a compile +// where a sampler array index is also the loop float index. +class ForLoopUnrollMarker : public TIntermTraverser +{ + public: + enum UnrollCondition + { + kIntegerIndex, + kSamplerArrayIndex + }; + + ForLoopUnrollMarker(UnrollCondition condition) + : mUnrollCondition(condition), + mSamplerArrayIndexIsFloatLoopIndex(false), + mVisitSamplerArrayIndexNodeInsideLoop(false) + { + } + + virtual bool visitBinary(Visit, TIntermBinary *node); + virtual bool visitLoop(Visit, TIntermLoop *node); + virtual void visitSymbol(TIntermSymbol *node); + + bool samplerArrayIndexIsFloatLoopIndex() const + { + return mSamplerArrayIndexIsFloatLoopIndex; + } + + private: + UnrollCondition mUnrollCondition; + TLoopStack mLoopStack; + bool mSamplerArrayIndexIsFloatLoopIndex; + bool mVisitSamplerArrayIndexNodeInsideLoop; }; #endif diff --git a/src/3rdparty/angle/src/compiler/translator/HashNames.h b/src/3rdparty/angle/src/compiler/translator/HashNames.h index 751265b759..85161428b2 100644 --- a/src/3rdparty/angle/src/compiler/translator/HashNames.h +++ b/src/3rdparty/angle/src/compiler/translator/HashNames.h @@ -10,7 +10,6 @@ #include #include "compiler/translator/intermediate.h" -#include "GLSLANG/ShaderLang.h" #define HASHED_NAME_PREFIX "webgl_" diff --git a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp index db728b2129..e91d64f43b 100644 --- a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp @@ -1,11 +1,11 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // // -// Create strings that declare built-in definitions, add built-ins that +// Create symbols that declare built-in definitions, add built-ins that // cannot be expressed in the files, and establish mappings between // built-in functions and operators. // @@ -13,412 +13,589 @@ #include "compiler/translator/Initialize.h" #include "compiler/translator/intermediate.h" +#include "angle_gl.h" -void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable) +void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable) { - TType *float1 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 1); - TType *float2 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 2); - TType *float3 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 3); - TType *float4 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 4); + TType *float1 = new TType(EbtFloat); + TType *float2 = new TType(EbtFloat, 2); + TType *float3 = new TType(EbtFloat, 3); + TType *float4 = new TType(EbtFloat, 4); - TType *int2 = new TType(EbtInt, EbpUndefined, EvqGlobal, 2); - TType *int3 = new TType(EbtInt, EbpUndefined, EvqGlobal, 3); - TType *int4 = new TType(EbtInt, EbpUndefined, EvqGlobal, 4); + TType *int1 = new TType(EbtInt); + TType *int2 = new TType(EbtInt, 2); + TType *int3 = new TType(EbtInt, 3); + TType *int4 = new TType(EbtInt, 4); // // Angle and Trigonometric Functions. // - symbolTable.insertBuiltIn(float1, "radians", float1); - symbolTable.insertBuiltIn(float2, "radians", float2); - symbolTable.insertBuiltIn(float3, "radians", float3); - symbolTable.insertBuiltIn(float4, "radians", float4); - - symbolTable.insertBuiltIn(float1, "degrees", float1); - symbolTable.insertBuiltIn(float2, "degrees", float2); - symbolTable.insertBuiltIn(float3, "degrees", float3); - symbolTable.insertBuiltIn(float4, "degrees", float4); - - symbolTable.insertBuiltIn(float1, "sin", float1); - symbolTable.insertBuiltIn(float2, "sin", float2); - symbolTable.insertBuiltIn(float3, "sin", float3); - symbolTable.insertBuiltIn(float4, "sin", float4); - - symbolTable.insertBuiltIn(float1, "cos", float1); - symbolTable.insertBuiltIn(float2, "cos", float2); - symbolTable.insertBuiltIn(float3, "cos", float3); - symbolTable.insertBuiltIn(float4, "cos", float4); - - symbolTable.insertBuiltIn(float1, "tan", float1); - symbolTable.insertBuiltIn(float2, "tan", float2); - symbolTable.insertBuiltIn(float3, "tan", float3); - symbolTable.insertBuiltIn(float4, "tan", float4); - - symbolTable.insertBuiltIn(float1, "asin", float1); - symbolTable.insertBuiltIn(float2, "asin", float2); - symbolTable.insertBuiltIn(float3, "asin", float3); - symbolTable.insertBuiltIn(float4, "asin", float4); - - symbolTable.insertBuiltIn(float1, "acos", float1); - symbolTable.insertBuiltIn(float2, "acos", float2); - symbolTable.insertBuiltIn(float3, "acos", float3); - symbolTable.insertBuiltIn(float4, "acos", float4); - - symbolTable.insertBuiltIn(float1, "atan", float1, float1); - symbolTable.insertBuiltIn(float2, "atan", float2, float2); - symbolTable.insertBuiltIn(float3, "atan", float3, float3); - symbolTable.insertBuiltIn(float4, "atan", float4, float4); - - symbolTable.insertBuiltIn(float1, "atan", float1); - symbolTable.insertBuiltIn(float2, "atan", float2); - symbolTable.insertBuiltIn(float3, "atan", float3); - symbolTable.insertBuiltIn(float4, "atan", float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "radians", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "radians", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "radians", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "radians", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "degrees", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "degrees", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "degrees", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "degrees", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sin", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sin", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sin", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sin", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "cos", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "cos", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "cos", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "cos", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "tan", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "tan", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "tan", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "tan", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "asin", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "asin", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "asin", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "asin", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "acos", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "acos", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "acos", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "acos", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "atan", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "atan", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "atan", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "atan", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "atan", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "atan", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "atan", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "atan", float4); // // Exponential Functions. // - symbolTable.insertBuiltIn(float1, "pow", float1, float1); - symbolTable.insertBuiltIn(float2, "pow", float2, float2); - symbolTable.insertBuiltIn(float3, "pow", float3, float3); - symbolTable.insertBuiltIn(float4, "pow", float4, float4); - - symbolTable.insertBuiltIn(float1, "exp", float1); - symbolTable.insertBuiltIn(float2, "exp", float2); - symbolTable.insertBuiltIn(float3, "exp", float3); - symbolTable.insertBuiltIn(float4, "exp", float4); - - symbolTable.insertBuiltIn(float1, "log", float1); - symbolTable.insertBuiltIn(float2, "log", float2); - symbolTable.insertBuiltIn(float3, "log", float3); - symbolTable.insertBuiltIn(float4, "log", float4); - - symbolTable.insertBuiltIn(float1, "exp2", float1); - symbolTable.insertBuiltIn(float2, "exp2", float2); - symbolTable.insertBuiltIn(float3, "exp2", float3); - symbolTable.insertBuiltIn(float4, "exp2", float4); - - symbolTable.insertBuiltIn(float1, "log2", float1); - symbolTable.insertBuiltIn(float2, "log2", float2); - symbolTable.insertBuiltIn(float3, "log2", float3); - symbolTable.insertBuiltIn(float4, "log2", float4); - - symbolTable.insertBuiltIn(float1, "sqrt", float1); - symbolTable.insertBuiltIn(float2, "sqrt", float2); - symbolTable.insertBuiltIn(float3, "sqrt", float3); - symbolTable.insertBuiltIn(float4, "sqrt", float4); - - symbolTable.insertBuiltIn(float1, "inversesqrt", float1); - symbolTable.insertBuiltIn(float2, "inversesqrt", float2); - symbolTable.insertBuiltIn(float3, "inversesqrt", float3); - symbolTable.insertBuiltIn(float4, "inversesqrt", float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "pow", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "pow", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "pow", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "pow", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "exp", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "exp", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "exp", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "exp", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "log", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "log", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "log", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "log", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "exp2", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "exp2", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "exp2", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "exp2", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "log2", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "log2", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "log2", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "log2", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sqrt", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sqrt", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sqrt", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sqrt", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "inversesqrt", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "inversesqrt", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "inversesqrt", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "inversesqrt", float4); // // Common Functions. // - symbolTable.insertBuiltIn(float1, "abs", float1); - symbolTable.insertBuiltIn(float2, "abs", float2); - symbolTable.insertBuiltIn(float3, "abs", float3); - symbolTable.insertBuiltIn(float4, "abs", float4); - - symbolTable.insertBuiltIn(float1, "sign", float1); - symbolTable.insertBuiltIn(float2, "sign", float2); - symbolTable.insertBuiltIn(float3, "sign", float3); - symbolTable.insertBuiltIn(float4, "sign", float4); - - symbolTable.insertBuiltIn(float1, "floor", float1); - symbolTable.insertBuiltIn(float2, "floor", float2); - symbolTable.insertBuiltIn(float3, "floor", float3); - symbolTable.insertBuiltIn(float4, "floor", float4); - - symbolTable.insertBuiltIn(float1, "ceil", float1); - symbolTable.insertBuiltIn(float2, "ceil", float2); - symbolTable.insertBuiltIn(float3, "ceil", float3); - symbolTable.insertBuiltIn(float4, "ceil", float4); - - symbolTable.insertBuiltIn(float1, "fract", float1); - symbolTable.insertBuiltIn(float2, "fract", float2); - symbolTable.insertBuiltIn(float3, "fract", float3); - symbolTable.insertBuiltIn(float4, "fract", float4); - - symbolTable.insertBuiltIn(float1, "mod", float1, float1); - symbolTable.insertBuiltIn(float2, "mod", float2, float1); - symbolTable.insertBuiltIn(float3, "mod", float3, float1); - symbolTable.insertBuiltIn(float4, "mod", float4, float1); - symbolTable.insertBuiltIn(float2, "mod", float2, float2); - symbolTable.insertBuiltIn(float3, "mod", float3, float3); - symbolTable.insertBuiltIn(float4, "mod", float4, float4); - - symbolTable.insertBuiltIn(float1, "min", float1, float1); - symbolTable.insertBuiltIn(float2, "min", float2, float1); - symbolTable.insertBuiltIn(float3, "min", float3, float1); - symbolTable.insertBuiltIn(float4, "min", float4, float1); - symbolTable.insertBuiltIn(float2, "min", float2, float2); - symbolTable.insertBuiltIn(float3, "min", float3, float3); - symbolTable.insertBuiltIn(float4, "min", float4, float4); - - symbolTable.insertBuiltIn(float1, "max", float1, float1); - symbolTable.insertBuiltIn(float2, "max", float2, float1); - symbolTable.insertBuiltIn(float3, "max", float3, float1); - symbolTable.insertBuiltIn(float4, "max", float4, float1); - symbolTable.insertBuiltIn(float2, "max", float2, float2); - symbolTable.insertBuiltIn(float3, "max", float3, float3); - symbolTable.insertBuiltIn(float4, "max", float4, float4); - - symbolTable.insertBuiltIn(float1, "clamp", float1, float1, float1); - symbolTable.insertBuiltIn(float2, "clamp", float2, float1, float1); - symbolTable.insertBuiltIn(float3, "clamp", float3, float1, float1); - symbolTable.insertBuiltIn(float4, "clamp", float4, float1, float1); - symbolTable.insertBuiltIn(float2, "clamp", float2, float2, float2); - symbolTable.insertBuiltIn(float3, "clamp", float3, float3, float3); - symbolTable.insertBuiltIn(float4, "clamp", float4, float4, float4); - - symbolTable.insertBuiltIn(float1, "mix", float1, float1, float1); - symbolTable.insertBuiltIn(float2, "mix", float2, float2, float1); - symbolTable.insertBuiltIn(float3, "mix", float3, float3, float1); - symbolTable.insertBuiltIn(float4, "mix", float4, float4, float1); - symbolTable.insertBuiltIn(float2, "mix", float2, float2, float2); - symbolTable.insertBuiltIn(float3, "mix", float3, float3, float3); - symbolTable.insertBuiltIn(float4, "mix", float4, float4, float4); - - symbolTable.insertBuiltIn(float1, "step", float1, float1); - symbolTable.insertBuiltIn(float2, "step", float2, float2); - symbolTable.insertBuiltIn(float3, "step", float3, float3); - symbolTable.insertBuiltIn(float4, "step", float4, float4); - symbolTable.insertBuiltIn(float2, "step", float1, float2); - symbolTable.insertBuiltIn(float3, "step", float1, float3); - symbolTable.insertBuiltIn(float4, "step", float1, float4); - - symbolTable.insertBuiltIn(float1, "smoothstep", float1, float1, float1); - symbolTable.insertBuiltIn(float2, "smoothstep", float2, float2, float2); - symbolTable.insertBuiltIn(float3, "smoothstep", float3, float3, float3); - symbolTable.insertBuiltIn(float4, "smoothstep", float4, float4, float4); - symbolTable.insertBuiltIn(float2, "smoothstep", float1, float1, float2); - symbolTable.insertBuiltIn(float3, "smoothstep", float1, float1, float3); - symbolTable.insertBuiltIn(float4, "smoothstep", float1, float1, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "abs", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "abs", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "abs", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "abs", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sign", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sign", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sign", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sign", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "floor", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "floor", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "floor", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "floor", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "ceil", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "ceil", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "ceil", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "ceil", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "fract", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "fract", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "fract", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "fract", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "mod", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mod", float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mod", float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mod", float4, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mod", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mod", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mod", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "min", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "min", float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "min", float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "min", float4, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "min", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "min", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "min", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "max", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "max", float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "max", float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "max", float4, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "max", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "max", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "max", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "clamp", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "clamp", float2, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "clamp", float3, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "clamp", float4, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "clamp", float2, float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "clamp", float3, float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "clamp", float4, float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "mix", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mix", float2, float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mix", float3, float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mix", float4, float4, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mix", float2, float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mix", float3, float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mix", float4, float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "step", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "step", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "step", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "step", float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "step", float1, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "step", float1, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "step", float1, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "smoothstep", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "smoothstep", float2, float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "smoothstep", float3, float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "smoothstep", float4, float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "smoothstep", float1, float1, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "smoothstep", float1, float1, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "smoothstep", float1, float1, float4); // // Geometric Functions. // - symbolTable.insertBuiltIn(float1, "length", float1); - symbolTable.insertBuiltIn(float1, "length", float2); - symbolTable.insertBuiltIn(float1, "length", float3); - symbolTable.insertBuiltIn(float1, "length", float4); - - symbolTable.insertBuiltIn(float1, "distance", float1, float1); - symbolTable.insertBuiltIn(float1, "distance", float2, float2); - symbolTable.insertBuiltIn(float1, "distance", float3, float3); - symbolTable.insertBuiltIn(float1, "distance", float4, float4); - - symbolTable.insertBuiltIn(float1, "dot", float1, float1); - symbolTable.insertBuiltIn(float1, "dot", float2, float2); - symbolTable.insertBuiltIn(float1, "dot", float3, float3); - symbolTable.insertBuiltIn(float1, "dot", float4, float4); - - symbolTable.insertBuiltIn(float3, "cross", float3, float3); - symbolTable.insertBuiltIn(float1, "normalize", float1); - symbolTable.insertBuiltIn(float2, "normalize", float2); - symbolTable.insertBuiltIn(float3, "normalize", float3); - symbolTable.insertBuiltIn(float4, "normalize", float4); - - symbolTable.insertBuiltIn(float1, "faceforward", float1, float1, float1); - symbolTable.insertBuiltIn(float2, "faceforward", float2, float2, float2); - symbolTable.insertBuiltIn(float3, "faceforward", float3, float3, float3); - symbolTable.insertBuiltIn(float4, "faceforward", float4, float4, float4); - - symbolTable.insertBuiltIn(float1, "reflect", float1, float1); - symbolTable.insertBuiltIn(float2, "reflect", float2, float2); - symbolTable.insertBuiltIn(float3, "reflect", float3, float3); - symbolTable.insertBuiltIn(float4, "reflect", float4, float4); - - symbolTable.insertBuiltIn(float1, "refract", float1, float1, float1); - symbolTable.insertBuiltIn(float2, "refract", float2, float2, float1); - symbolTable.insertBuiltIn(float3, "refract", float3, float3, float1); - symbolTable.insertBuiltIn(float4, "refract", float4, float4, float1); - - TType *mat2 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 2, true); - TType *mat3 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 3, true); - TType *mat4 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 4, true); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "cross", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "normalize", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "normalize", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "normalize", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "normalize", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "faceforward", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "faceforward", float2, float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "faceforward", float3, float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "faceforward", float4, float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "reflect", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "reflect", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "reflect", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "reflect", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "refract", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "refract", float2, float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "refract", float3, float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "refract", float4, float4, float1); + + TType *mat2 = new TType(EbtFloat, 2, 2); + TType *mat3 = new TType(EbtFloat, 3, 3); + TType *mat4 = new TType(EbtFloat, 4, 4); // // Matrix Functions. // - symbolTable.insertBuiltIn(mat2, "matrixCompMult", mat2, mat2); - symbolTable.insertBuiltIn(mat3, "matrixCompMult", mat3, mat3); - symbolTable.insertBuiltIn(mat4, "matrixCompMult", mat4, mat4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, mat2, "matrixCompMult", mat2, mat2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, mat3, "matrixCompMult", mat3, mat3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, mat4, "matrixCompMult", mat4, mat4); - TType *bool1 = new TType(EbtBool, EbpUndefined, EvqGlobal, 1); - TType *bool2 = new TType(EbtBool, EbpUndefined, EvqGlobal, 2); - TType *bool3 = new TType(EbtBool, EbpUndefined, EvqGlobal, 3); - TType *bool4 = new TType(EbtBool, EbpUndefined, EvqGlobal, 4); + TType *bool1 = new TType(EbtBool); + TType *bool2 = new TType(EbtBool, 2); + TType *bool3 = new TType(EbtBool, 3); + TType *bool4 = new TType(EbtBool, 4); // // Vector relational functions. // - symbolTable.insertBuiltIn(bool2, "lessThan", float2, float2); - symbolTable.insertBuiltIn(bool3, "lessThan", float3, float3); - symbolTable.insertBuiltIn(bool4, "lessThan", float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThan", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThan", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThan", float4, float4); - symbolTable.insertBuiltIn(bool2, "lessThan", int2, int2); - symbolTable.insertBuiltIn(bool3, "lessThan", int3, int3); - symbolTable.insertBuiltIn(bool4, "lessThan", int4, int4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThan", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThan", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThan", int4, int4); - symbolTable.insertBuiltIn(bool2, "lessThanEqual", float2, float2); - symbolTable.insertBuiltIn(bool3, "lessThanEqual", float3, float3); - symbolTable.insertBuiltIn(bool4, "lessThanEqual", float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThanEqual", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThanEqual", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThanEqual", float4, float4); - symbolTable.insertBuiltIn(bool2, "lessThanEqual", int2, int2); - symbolTable.insertBuiltIn(bool3, "lessThanEqual", int3, int3); - symbolTable.insertBuiltIn(bool4, "lessThanEqual", int4, int4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThanEqual", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThanEqual", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThanEqual", int4, int4); - symbolTable.insertBuiltIn(bool2, "greaterThan", float2, float2); - symbolTable.insertBuiltIn(bool3, "greaterThan", float3, float3); - symbolTable.insertBuiltIn(bool4, "greaterThan", float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThan", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThan", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThan", float4, float4); - symbolTable.insertBuiltIn(bool2, "greaterThan", int2, int2); - symbolTable.insertBuiltIn(bool3, "greaterThan", int3, int3); - symbolTable.insertBuiltIn(bool4, "greaterThan", int4, int4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThan", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThan", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThan", int4, int4); - symbolTable.insertBuiltIn(bool2, "greaterThanEqual", float2, float2); - symbolTable.insertBuiltIn(bool3, "greaterThanEqual", float3, float3); - symbolTable.insertBuiltIn(bool4, "greaterThanEqual", float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThanEqual", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThanEqual", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThanEqual", float4, float4); - symbolTable.insertBuiltIn(bool2, "greaterThanEqual", int2, int2); - symbolTable.insertBuiltIn(bool3, "greaterThanEqual", int3, int3); - symbolTable.insertBuiltIn(bool4, "greaterThanEqual", int4, int4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThanEqual", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThanEqual", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThanEqual", int4, int4); - symbolTable.insertBuiltIn(bool2, "equal", float2, float2); - symbolTable.insertBuiltIn(bool3, "equal", float3, float3); - symbolTable.insertBuiltIn(bool4, "equal", float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", float4, float4); - symbolTable.insertBuiltIn(bool2, "equal", int2, int2); - symbolTable.insertBuiltIn(bool3, "equal", int3, int3); - symbolTable.insertBuiltIn(bool4, "equal", int4, int4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", int4, int4); - symbolTable.insertBuiltIn(bool2, "equal", bool2, bool2); - symbolTable.insertBuiltIn(bool3, "equal", bool3, bool3); - symbolTable.insertBuiltIn(bool4, "equal", bool4, bool4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", bool2, bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", bool3, bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", bool4, bool4); - symbolTable.insertBuiltIn(bool2, "notEqual", float2, float2); - symbolTable.insertBuiltIn(bool3, "notEqual", float3, float3); - symbolTable.insertBuiltIn(bool4, "notEqual", float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", float4, float4); - symbolTable.insertBuiltIn(bool2, "notEqual", int2, int2); - symbolTable.insertBuiltIn(bool3, "notEqual", int3, int3); - symbolTable.insertBuiltIn(bool4, "notEqual", int4, int4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", int4, int4); - symbolTable.insertBuiltIn(bool2, "notEqual", bool2, bool2); - symbolTable.insertBuiltIn(bool3, "notEqual", bool3, bool3); - symbolTable.insertBuiltIn(bool4, "notEqual", bool4, bool4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", bool2, bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", bool3, bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", bool4, bool4); - symbolTable.insertBuiltIn(bool1, "any", bool2); - symbolTable.insertBuiltIn(bool1, "any", bool3); - symbolTable.insertBuiltIn(bool1, "any", bool4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool4); - symbolTable.insertBuiltIn(bool1, "all", bool2); - symbolTable.insertBuiltIn(bool1, "all", bool3); - symbolTable.insertBuiltIn(bool1, "all", bool4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool4); - symbolTable.insertBuiltIn(bool2, "not", bool2); - symbolTable.insertBuiltIn(bool3, "not", bool3); - symbolTable.insertBuiltIn(bool4, "not", bool4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "not", bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "not", bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "not", bool4); - TType *sampler2D = new TType(EbtSampler2D, EbpUndefined, EvqGlobal, 1); - TType *samplerCube = new TType(EbtSamplerCube, EbpUndefined, EvqGlobal, 1); + TType *sampler2D = new TType(EbtSampler2D); + TType *samplerCube = new TType(EbtSamplerCube); // // Texture Functions for GLSL ES 1.0 // - symbolTable.insertBuiltIn(float4, "texture2D", sampler2D, float2); - symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float3); - symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float4); - symbolTable.insertBuiltIn(float4, "textureCube", samplerCube, float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", sampler2D, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3); if (resources.OES_EGL_image_external) { - TType *samplerExternalOES = new TType(EbtSamplerExternalOES, EbpUndefined, EvqGlobal, 1); + TType *samplerExternalOES = new TType(EbtSamplerExternalOES); - symbolTable.insertBuiltIn(float4, "texture2D", samplerExternalOES, float2); - symbolTable.insertBuiltIn(float4, "texture2DProj", samplerExternalOES, float3); - symbolTable.insertBuiltIn(float4, "texture2DProj", samplerExternalOES, float4); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", samplerExternalOES, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float4); } if (resources.ARB_texture_rectangle) { - TType *sampler2DRect = new TType(EbtSampler2DRect, EbpUndefined, EvqGlobal, 1); + TType *sampler2DRect = new TType(EbtSampler2DRect); - symbolTable.insertBuiltIn(float4, "texture2DRect", sampler2DRect, float2); - symbolTable.insertBuiltIn(float4, "texture2DRectProj", sampler2DRect, float3); - symbolTable.insertBuiltIn(float4, "texture2DRectProj", sampler2DRect, float4); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRect", sampler2DRect, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float4); } - if (type == SH_FRAGMENT_SHADER) + if (resources.EXT_shader_texture_lod) { - symbolTable.insertBuiltIn(float4, "texture2D", sampler2D, float2, float1); - symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float3, float1); - symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float4, float1); - symbolTable.insertBuiltIn(float4, "textureCube", samplerCube, float3, float1); + /* The *Grad* variants are new to both vertex and fragment shaders; the fragment + * shader specific pieces are added separately below. + */ + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DGradEXT", sampler2D, float2, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeGradEXT", samplerCube, float3, float3, float3); + } + + if (type == GL_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", sampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3, float1); if (resources.OES_standard_derivatives) { - symbolTable.insertBuiltIn(float1, "dFdx", float1); - symbolTable.insertBuiltIn(float2, "dFdx", float2); - symbolTable.insertBuiltIn(float3, "dFdx", float3); - symbolTable.insertBuiltIn(float4, "dFdx", float4); - - symbolTable.insertBuiltIn(float1, "dFdy", float1); - symbolTable.insertBuiltIn(float2, "dFdy", float2); - symbolTable.insertBuiltIn(float3, "dFdy", float3); - symbolTable.insertBuiltIn(float4, "dFdy", float4); - - symbolTable.insertBuiltIn(float1, "fwidth", float1); - symbolTable.insertBuiltIn(float2, "fwidth", float2); - symbolTable.insertBuiltIn(float3, "fwidth", float3); - symbolTable.insertBuiltIn(float4, "fwidth", float4); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "dFdx", float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "dFdx", float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "dFdx", float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "dFdx", float4); + + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "dFdy", float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "dFdy", float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "dFdy", float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "dFdy", float4); + + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "fwidth", float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "fwidth", float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "fwidth", float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "fwidth", float4); + } + + if (resources.EXT_shader_texture_lod) + { + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLodEXT", sampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLodEXT", samplerCube, float3, float1); } } - if(type == SH_VERTEX_SHADER) + if(type == GL_VERTEX_SHADER) { - symbolTable.insertBuiltIn(float4, "texture2DLod", sampler2D, float2, float1); - symbolTable.insertBuiltIn(float4, "texture2DProjLod", sampler2D, float3, float1); - symbolTable.insertBuiltIn(float4, "texture2DProjLod", sampler2D, float4, float1); - symbolTable.insertBuiltIn(float4, "textureCubeLod", samplerCube, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLod", sampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLod", samplerCube, float3, float1); } + TType *gvec4 = new TType(EbtGVec4); + + TType *gsampler2D = new TType(EbtGSampler2D); + TType *gsamplerCube = new TType(EbtGSamplerCube); + TType *gsampler3D = new TType(EbtGSampler3D); + TType *gsampler2DArray = new TType(EbtGSampler2DArray); + + // + // Texture Functions for GLSL ES 3.0 + // + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler3D, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsamplerCube, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler3D, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsamplerCube, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2DArray, float3, float1); + + if (type == GL_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler3D, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsamplerCube, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4, float1); + } + + TType *sampler2DShadow = new TType(EbtSampler2DShadow); + TType *samplerCubeShadow = new TType(EbtSamplerCubeShadow); + TType *sampler2DArrayShadow = new TType(EbtSampler2DArrayShadow); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DArrayShadow, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLod", sampler2DShadow, float3, float1); + + if (type == GL_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4, float1); + } + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsampler2D, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", gsampler3D, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsamplerCube, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", gsampler2DArray, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", sampler2DShadow, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerCubeShadow, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler2DArrayShadow, int1); + + if(type == GL_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "dFdx", float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "dFdx", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "dFdx", float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "dFdx", float4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "dFdy", float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "dFdy", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "dFdy", float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "dFdy", float4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "fwidth", float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "fwidth", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "fwidth", float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "fwidth", float4); + } + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2); + + if(type == GL_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2, float1); + } + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2); + + if(type == GL_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2, float1); + } + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2D, float2, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler3D, float3, float1, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLodOffset", sampler2DShadow, float3, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2DArray, float3, float1, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler3D, float4, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLod", sampler2DShadow, float4, float1); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float3, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float4, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler3D, float4, float1, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLodOffset", sampler2DShadow, float4, float1, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2D, int2, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler3D, int3, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2DArray, int3, int1); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2D, int2, int1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler3D, int3, int1, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2DArray, int3, int1, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2D, float2, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler3D, float3, float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsamplerCube, float3, float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DShadow, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", samplerCubeShadow, float4, float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2DArray, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DArrayShadow, float4, float2, float2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2D, float2, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler3D, float3, float3, float3, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DShadow, float3, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2DArray, float3, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DArrayShadow, float4, float2, float2, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float4, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler3D, float4, float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGrad", sampler2DShadow, float4, float2, float2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float3, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float4, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler3D, float4, float3, float3, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow, float4, float2, float2, int2); + // // Depth range in window coordinates // TFieldList *fields = NewPoolTFieldList(); - TField *near = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("near")); - TField *far = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("far")); - TField *diff = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("diff")); + TSourceLoc zeroSourceLoc = {0, 0, 0, 0}; + TField *near = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("near"), zeroSourceLoc); + TField *far = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("far"), zeroSourceLoc); + TField *diff = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("diff"), zeroSourceLoc); fields->push_back(near); fields->push_back(far); fields->push_back(diff); TStructure *depthRangeStruct = new TStructure(NewPoolTString("gl_DepthRangeParameters"), fields); TVariable *depthRangeParameters = new TVariable(&depthRangeStruct->name(), depthRangeStruct, true); - symbolTable.insert(*depthRangeParameters); + symbolTable.insert(COMMON_BUILTINS, depthRangeParameters); TVariable *depthRange = new TVariable(NewPoolTString("gl_DepthRange"), TType(depthRangeStruct)); depthRange->setQualifier(EvqUniform); - symbolTable.insert(*depthRange); + symbolTable.insert(COMMON_BUILTINS, depthRange); // // Implementation dependent built-in constants. // - symbolTable.insertConstInt("gl_MaxVertexAttribs", resources.MaxVertexAttribs); - symbolTable.insertConstInt("gl_MaxVertexUniformVectors", resources.MaxVertexUniformVectors); - symbolTable.insertConstInt("gl_MaxVaryingVectors", resources.MaxVaryingVectors); - symbolTable.insertConstInt("gl_MaxVertexTextureImageUnits", resources.MaxVertexTextureImageUnits); - symbolTable.insertConstInt("gl_MaxCombinedTextureImageUnits", resources.MaxCombinedTextureImageUnits); - symbolTable.insertConstInt("gl_MaxTextureImageUnits", resources.MaxTextureImageUnits); - symbolTable.insertConstInt("gl_MaxFragmentUniformVectors", resources.MaxFragmentUniformVectors); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexAttribs", resources.MaxVertexAttribs); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexUniformVectors", resources.MaxVertexUniformVectors); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexTextureImageUnits", resources.MaxVertexTextureImageUnits); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxCombinedTextureImageUnits", resources.MaxCombinedTextureImageUnits); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits", resources.MaxTextureImageUnits); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors", resources.MaxFragmentUniformVectors); + + symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors); if (spec != SH_CSS_SHADERS_SPEC) { - symbolTable.insertConstInt("gl_MaxDrawBuffers", resources.MaxDrawBuffers); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers); } + + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", resources.MaxVertexOutputVectors); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors", resources.MaxFragmentInputVectors); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset", resources.MinProgramTexelOffset); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxProgramTexelOffset", resources.MaxProgramTexelOffset); } -void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, +void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable) { @@ -427,32 +604,32 @@ void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, // the built-in header files. // switch(type) { - case SH_FRAGMENT_SHADER: - symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4))); - symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1))); - symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2))); + case GL_FRAGMENT_SHADER: + symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4))); + symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1))); + symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2))); // // In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available. // Instead, css_MixColor and css_ColorMatrix are available. // if (spec != SH_CSS_SHADERS_SPEC) { - symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4))); - symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4))); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4))); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4))); if (resources.EXT_frag_depth) { - symbolTable.insert(*new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1))); - symbolTable.relateToExtension("gl_FragDepthEXT", "GL_EXT_frag_depth"); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1))); + symbolTable.relateToExtension(ESSL1_BUILTINS, "gl_FragDepthEXT", "GL_EXT_frag_depth"); } } else { - symbolTable.insert(*new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4))); - symbolTable.insert(*new TVariable(NewPoolTString("css_ColorMatrix"), TType(EbtFloat, EbpMedium, EvqGlobal, 4, true))); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4))); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_ColorMatrix"), TType(EbtFloat, EbpMedium, EvqGlobal, 4, 4))); } break; - case SH_VERTEX_SHADER: - symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4))); - symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1))); + case GL_VERTEX_SHADER: + symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4))); + symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1))); break; default: assert(false && "Language not supported"); @@ -464,84 +641,102 @@ void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, // expected to be resolved through a library of functions, versus as // operations. // - symbolTable.relateToOperator("matrixCompMult", EOpMul); - - symbolTable.relateToOperator("equal", EOpVectorEqual); - symbolTable.relateToOperator("notEqual", EOpVectorNotEqual); - symbolTable.relateToOperator("lessThan", EOpLessThan); - symbolTable.relateToOperator("greaterThan", EOpGreaterThan); - symbolTable.relateToOperator("lessThanEqual", EOpLessThanEqual); - symbolTable.relateToOperator("greaterThanEqual", EOpGreaterThanEqual); - - symbolTable.relateToOperator("radians", EOpRadians); - symbolTable.relateToOperator("degrees", EOpDegrees); - symbolTable.relateToOperator("sin", EOpSin); - symbolTable.relateToOperator("cos", EOpCos); - symbolTable.relateToOperator("tan", EOpTan); - symbolTable.relateToOperator("asin", EOpAsin); - symbolTable.relateToOperator("acos", EOpAcos); - symbolTable.relateToOperator("atan", EOpAtan); - - symbolTable.relateToOperator("pow", EOpPow); - symbolTable.relateToOperator("exp2", EOpExp2); - symbolTable.relateToOperator("log", EOpLog); - symbolTable.relateToOperator("exp", EOpExp); - symbolTable.relateToOperator("log2", EOpLog2); - symbolTable.relateToOperator("sqrt", EOpSqrt); - symbolTable.relateToOperator("inversesqrt", EOpInverseSqrt); - - symbolTable.relateToOperator("abs", EOpAbs); - symbolTable.relateToOperator("sign", EOpSign); - symbolTable.relateToOperator("floor", EOpFloor); - symbolTable.relateToOperator("ceil", EOpCeil); - symbolTable.relateToOperator("fract", EOpFract); - symbolTable.relateToOperator("mod", EOpMod); - symbolTable.relateToOperator("min", EOpMin); - symbolTable.relateToOperator("max", EOpMax); - symbolTable.relateToOperator("clamp", EOpClamp); - symbolTable.relateToOperator("mix", EOpMix); - symbolTable.relateToOperator("step", EOpStep); - symbolTable.relateToOperator("smoothstep", EOpSmoothStep); - - symbolTable.relateToOperator("length", EOpLength); - symbolTable.relateToOperator("distance", EOpDistance); - symbolTable.relateToOperator("dot", EOpDot); - symbolTable.relateToOperator("cross", EOpCross); - symbolTable.relateToOperator("normalize", EOpNormalize); - symbolTable.relateToOperator("faceforward", EOpFaceForward); - symbolTable.relateToOperator("reflect", EOpReflect); - symbolTable.relateToOperator("refract", EOpRefract); + symbolTable.relateToOperator(COMMON_BUILTINS, "matrixCompMult", EOpMul); + + symbolTable.relateToOperator(COMMON_BUILTINS, "equal", EOpVectorEqual); + symbolTable.relateToOperator(COMMON_BUILTINS, "notEqual", EOpVectorNotEqual); + symbolTable.relateToOperator(COMMON_BUILTINS, "lessThan", EOpLessThan); + symbolTable.relateToOperator(COMMON_BUILTINS, "greaterThan", EOpGreaterThan); + symbolTable.relateToOperator(COMMON_BUILTINS, "lessThanEqual", EOpLessThanEqual); + symbolTable.relateToOperator(COMMON_BUILTINS, "greaterThanEqual", EOpGreaterThanEqual); - symbolTable.relateToOperator("any", EOpAny); - symbolTable.relateToOperator("all", EOpAll); - symbolTable.relateToOperator("not", EOpVectorLogicalNot); + symbolTable.relateToOperator(COMMON_BUILTINS, "radians", EOpRadians); + symbolTable.relateToOperator(COMMON_BUILTINS, "degrees", EOpDegrees); + symbolTable.relateToOperator(COMMON_BUILTINS, "sin", EOpSin); + symbolTable.relateToOperator(COMMON_BUILTINS, "cos", EOpCos); + symbolTable.relateToOperator(COMMON_BUILTINS, "tan", EOpTan); + symbolTable.relateToOperator(COMMON_BUILTINS, "asin", EOpAsin); + symbolTable.relateToOperator(COMMON_BUILTINS, "acos", EOpAcos); + symbolTable.relateToOperator(COMMON_BUILTINS, "atan", EOpAtan); + + symbolTable.relateToOperator(COMMON_BUILTINS, "pow", EOpPow); + symbolTable.relateToOperator(COMMON_BUILTINS, "exp2", EOpExp2); + symbolTable.relateToOperator(COMMON_BUILTINS, "log", EOpLog); + symbolTable.relateToOperator(COMMON_BUILTINS, "exp", EOpExp); + symbolTable.relateToOperator(COMMON_BUILTINS, "log2", EOpLog2); + symbolTable.relateToOperator(COMMON_BUILTINS, "sqrt", EOpSqrt); + symbolTable.relateToOperator(COMMON_BUILTINS, "inversesqrt", EOpInverseSqrt); + + symbolTable.relateToOperator(COMMON_BUILTINS, "abs", EOpAbs); + symbolTable.relateToOperator(COMMON_BUILTINS, "sign", EOpSign); + symbolTable.relateToOperator(COMMON_BUILTINS, "floor", EOpFloor); + symbolTable.relateToOperator(COMMON_BUILTINS, "ceil", EOpCeil); + symbolTable.relateToOperator(COMMON_BUILTINS, "fract", EOpFract); + symbolTable.relateToOperator(COMMON_BUILTINS, "mod", EOpMod); + symbolTable.relateToOperator(COMMON_BUILTINS, "min", EOpMin); + symbolTable.relateToOperator(COMMON_BUILTINS, "max", EOpMax); + symbolTable.relateToOperator(COMMON_BUILTINS, "clamp", EOpClamp); + symbolTable.relateToOperator(COMMON_BUILTINS, "mix", EOpMix); + symbolTable.relateToOperator(COMMON_BUILTINS, "step", EOpStep); + symbolTable.relateToOperator(COMMON_BUILTINS, "smoothstep", EOpSmoothStep); + + symbolTable.relateToOperator(COMMON_BUILTINS, "length", EOpLength); + symbolTable.relateToOperator(COMMON_BUILTINS, "distance", EOpDistance); + symbolTable.relateToOperator(COMMON_BUILTINS, "dot", EOpDot); + symbolTable.relateToOperator(COMMON_BUILTINS, "cross", EOpCross); + symbolTable.relateToOperator(COMMON_BUILTINS, "normalize", EOpNormalize); + symbolTable.relateToOperator(COMMON_BUILTINS, "faceforward", EOpFaceForward); + symbolTable.relateToOperator(COMMON_BUILTINS, "reflect", EOpReflect); + symbolTable.relateToOperator(COMMON_BUILTINS, "refract", EOpRefract); + + symbolTable.relateToOperator(COMMON_BUILTINS, "any", EOpAny); + symbolTable.relateToOperator(COMMON_BUILTINS, "all", EOpAll); + symbolTable.relateToOperator(COMMON_BUILTINS, "not", EOpVectorLogicalNot); // Map language-specific operators. switch(type) { - case SH_VERTEX_SHADER: + case GL_VERTEX_SHADER: break; - case SH_FRAGMENT_SHADER: - if (resources.OES_standard_derivatives) { - symbolTable.relateToOperator("dFdx", EOpDFdx); - symbolTable.relateToOperator("dFdy", EOpDFdy); - symbolTable.relateToOperator("fwidth", EOpFwidth); - - symbolTable.relateToExtension("dFdx", "GL_OES_standard_derivatives"); - symbolTable.relateToExtension("dFdy", "GL_OES_standard_derivatives"); - symbolTable.relateToExtension("fwidth", "GL_OES_standard_derivatives"); + case GL_FRAGMENT_SHADER: + if (resources.OES_standard_derivatives) + { + symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdx", EOpDFdx); + symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdy", EOpDFdy); + symbolTable.relateToOperator(ESSL1_BUILTINS, "fwidth", EOpFwidth); + + symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdx", "GL_OES_standard_derivatives"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdy", "GL_OES_standard_derivatives"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "fwidth", "GL_OES_standard_derivatives"); + } + if (resources.EXT_shader_texture_lod) + { + symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DLodEXT", "GL_EXT_shader_texture_lod"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjLodEXT", "GL_EXT_shader_texture_lod"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeLodEXT", "GL_EXT_shader_texture_lod"); } break; default: break; } + symbolTable.relateToOperator(ESSL3_BUILTINS, "dFdx", EOpDFdx); + symbolTable.relateToOperator(ESSL3_BUILTINS, "dFdy", EOpDFdy); + symbolTable.relateToOperator(ESSL3_BUILTINS, "fwidth", EOpFwidth); + + if (resources.EXT_shader_texture_lod) + { + symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DGradEXT", "GL_EXT_shader_texture_lod"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjGradEXT", "GL_EXT_shader_texture_lod"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeGradEXT", "GL_EXT_shader_texture_lod"); + } + // Finally add resource-specific variables. switch(type) { - case SH_FRAGMENT_SHADER: + case GL_FRAGMENT_SHADER: if (spec != SH_CSS_SHADERS_SPEC) { // Set up gl_FragData. The array size. - TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, false, true); + TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true); fragData.setArraySize(resources.MaxDrawBuffers); - symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData)); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData)); } break; default: break; @@ -561,4 +756,6 @@ void InitExtensionBehavior(const ShBuiltInResources& resources, extBehavior["GL_EXT_draw_buffers"] = EBhUndefined; if (resources.EXT_frag_depth) extBehavior["GL_EXT_frag_depth"] = EBhUndefined; + if (resources.EXT_shader_texture_lod) + extBehavior["GL_EXT_shader_texture_lod"] = EBhUndefined; } diff --git a/src/3rdparty/angle/src/compiler/translator/Initialize.h b/src/3rdparty/angle/src/compiler/translator/Initialize.h index b5642869aa..cc1862c90e 100644 --- a/src/3rdparty/angle/src/compiler/translator/Initialize.h +++ b/src/3rdparty/angle/src/compiler/translator/Initialize.h @@ -8,12 +8,12 @@ #define _INITIALIZE_INCLUDED_ #include "compiler/translator/Common.h" -#include "compiler/translator/ShHandle.h" +#include "compiler/translator/Compiler.h" #include "compiler/translator/SymbolTable.h" -void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &table); +void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &table); -void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, +void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources& resources, TSymbolTable& symbolTable); diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp b/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp index 43f81784d0..c98430662a 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp +++ b/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp @@ -5,10 +5,12 @@ // #include "compiler/translator/InitializeDll.h" - #include "compiler/translator/InitializeGlobals.h" #include "compiler/translator/InitializeParseContext.h" -#include "compiler/translator/osinclude.h" + +#include "common/platform.h" + +#include bool InitProcess() { diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.cpp b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.cpp index b4defae569..c35cedb348 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.cpp +++ b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.cpp @@ -6,35 +6,37 @@ #include "compiler/translator/InitializeParseContext.h" -#include "compiler/translator/osinclude.h" +#include "common/tls.h" -OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX; +#include + +TLSIndex GlobalParseContextIndex = TLS_INVALID_INDEX; bool InitializeParseContextIndex() { - assert(GlobalParseContextIndex == OS_INVALID_TLS_INDEX); + assert(GlobalParseContextIndex == TLS_INVALID_INDEX); - GlobalParseContextIndex = OS_AllocTLSIndex(); - return GlobalParseContextIndex != OS_INVALID_TLS_INDEX; + GlobalParseContextIndex = CreateTLSIndex(); + return GlobalParseContextIndex != TLS_INVALID_INDEX; } void FreeParseContextIndex() { - assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX); + assert(GlobalParseContextIndex != TLS_INVALID_INDEX); - OS_FreeTLSIndex(GlobalParseContextIndex); - GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + DestroyTLSIndex(GlobalParseContextIndex); + GlobalParseContextIndex = TLS_INVALID_INDEX; } void SetGlobalParseContext(TParseContext* context) { - assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX); - OS_SetTLSValue(GlobalParseContextIndex, context); + assert(GlobalParseContextIndex != TLS_INVALID_INDEX); + SetTLSValue(GlobalParseContextIndex, context); } TParseContext* GetGlobalParseContext() { - assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX); - return static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + assert(GlobalParseContextIndex != TLS_INVALID_INDEX); + return static_cast(GetTLSValue(GlobalParseContextIndex)); } diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp index 115c561c77..0e3e2ebe55 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp +++ b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp @@ -10,7 +10,7 @@ namespace { -TIntermConstantUnion* constructFloatConstUnionNode(const TType& type) +TIntermConstantUnion *constructFloatConstUnionNode(const TType &type) { TType myType = type; unsigned char size = myType.getNominalSize(); @@ -26,7 +26,7 @@ TIntermConstantUnion* constructFloatConstUnionNode(const TType& type) return node; } -TIntermConstantUnion* constructIndexNode(int index) +TIntermConstantUnion *constructIndexNode(int index) { ConstantUnion *u = new ConstantUnion[1]; u[0].setIConst(index); @@ -38,7 +38,7 @@ TIntermConstantUnion* constructIndexNode(int index) } // namespace anonymous -bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate* node) +bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node) { bool visitChildren = !mCodeInserted; switch (node->getOp()) @@ -51,17 +51,17 @@ bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate* node) ASSERT(visit == PreVisit); if (node->getName() == "main(") { - TIntermSequence &sequence = node->getSequence(); - ASSERT((sequence.size() == 1) || (sequence.size() == 2)); + TIntermSequence *sequence = node->getSequence(); + ASSERT((sequence->size() == 1) || (sequence->size() == 2)); TIntermAggregate *body = NULL; - if (sequence.size() == 1) + if (sequence->size() == 1) { body = new TIntermAggregate(EOpSequence); - sequence.push_back(body); + sequence->push_back(body); } else { - body = sequence[1]->getAsAggregate(); + body = (*sequence)[1]->getAsAggregate(); } ASSERT(body); insertInitCode(body->getSequence()); @@ -76,18 +76,18 @@ bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate* node) return visitChildren; } -void InitializeVariables::insertInitCode(TIntermSequence& sequence) +void InitializeVariables::insertInitCode(TIntermSequence *sequence) { for (size_t ii = 0; ii < mVariables.size(); ++ii) { - const InitVariableInfo& varInfo = mVariables[ii]; + const InitVariableInfo &varInfo = mVariables[ii]; if (varInfo.type.isArray()) { for (int index = varInfo.type.getArraySize() - 1; index >= 0; --index) { TIntermBinary *assign = new TIntermBinary(EOpAssign); - sequence.insert(sequence.begin(), assign); + sequence->insert(sequence->begin(), assign); TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect); TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type); @@ -104,7 +104,7 @@ void InitializeVariables::insertInitCode(TIntermSequence& sequence) else { TIntermBinary *assign = new TIntermBinary(EOpAssign); - sequence.insert(sequence.begin(), assign); + sequence->insert(sequence->begin(), assign); TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type); assign->setLeft(symbol); TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type); diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h index 1cd6d7e1b5..81ab9fe90f 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h @@ -17,7 +17,7 @@ class InitializeVariables : public TIntermTraverser TString name; TType type; - InitVariableInfo(const TString& _name, const TType& _type) + InitVariableInfo(const TString &_name, const TType &_type) : name(_name), type(_type) { @@ -25,23 +25,23 @@ class InitializeVariables : public TIntermTraverser }; typedef TVector InitVariableInfoList; - InitializeVariables(const InitVariableInfoList& vars) + InitializeVariables(const InitVariableInfoList &vars) : mCodeInserted(false), mVariables(vars) { } protected: - virtual bool visitBinary(Visit visit, TIntermBinary* node) { return false; } - virtual bool visitUnary(Visit visit, TIntermUnary* node) { return false; } - virtual bool visitSelection(Visit visit, TIntermSelection* node) { return false; } - virtual bool visitLoop(Visit visit, TIntermLoop* node) { return false; } - virtual bool visitBranch(Visit visit, TIntermBranch* node) { return false; } + virtual bool visitBinary(Visit, TIntermBinary *node) { return false; } + virtual bool visitUnary(Visit, TIntermUnary *node) { return false; } + virtual bool visitSelection(Visit, TIntermSelection *node) { return false; } + virtual bool visitLoop(Visit, TIntermLoop *node) { return false; } + virtual bool visitBranch(Visit, TIntermBranch *node) { return false; } virtual bool visitAggregate(Visit visit, TIntermAggregate* node); private: - void insertInitCode(TIntermSequence& sequence); + void insertInitCode(TIntermSequence *sequence); InitVariableInfoList mVariables; bool mCodeInserted; diff --git a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp index 554b83409a..48d2013cc5 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp +++ b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp @@ -45,7 +45,7 @@ void TIntermBinary::traverse(TIntermTraverser *it) // if (it->preVisit) visit = it->visitBinary(PreVisit, this); - + // // Visit the children, in the right order. // @@ -53,27 +53,27 @@ void TIntermBinary::traverse(TIntermTraverser *it) { it->incrementDepth(this); - if (it->rightToLeft) + if (it->rightToLeft) { - if (right) - right->traverse(it); - + if (mRight) + mRight->traverse(it); + if (it->inVisit) visit = it->visitBinary(InVisit, this); - if (visit && left) - left->traverse(it); + if (visit && mLeft) + mLeft->traverse(it); } else { - if (left) - left->traverse(it); - + if (mLeft) + mLeft->traverse(it); + if (it->inVisit) visit = it->visitBinary(InVisit, this); - if (visit && right) - right->traverse(it); + if (visit && mRight) + mRight->traverse(it); } it->decrementDepth(); @@ -99,10 +99,10 @@ void TIntermUnary::traverse(TIntermTraverser *it) if (visit) { it->incrementDepth(this); - operand->traverse(it); + mOperand->traverse(it); it->decrementDepth(); } - + if (visit && it->postVisit) it->visitUnary(PostVisit, this); } @@ -113,41 +113,43 @@ void TIntermUnary::traverse(TIntermTraverser *it) void TIntermAggregate::traverse(TIntermTraverser *it) { bool visit = true; - + if (it->preVisit) visit = it->visitAggregate(PreVisit, this); - + if (visit) { it->incrementDepth(this); if (it->rightToLeft) { - for (TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++) + for (TIntermSequence::reverse_iterator sit = mSequence.rbegin(); + sit != mSequence.rend(); sit++) { (*sit)->traverse(it); if (visit && it->inVisit) { - if (*sit != sequence.front()) + if (*sit != mSequence.front()) visit = it->visitAggregate(InVisit, this); } } } else { - for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + for (TIntermSequence::iterator sit = mSequence.begin(); + sit != mSequence.end(); sit++) { (*sit)->traverse(it); if (visit && it->inVisit) { - if (*sit != sequence.back()) + if (*sit != mSequence.back()) visit = it->visitAggregate(InVisit, this); } } } - + it->decrementDepth(); } @@ -164,21 +166,25 @@ void TIntermSelection::traverse(TIntermTraverser *it) if (it->preVisit) visit = it->visitSelection(PreVisit, this); - - if (visit) { + + if (visit) + { it->incrementDepth(this); - if (it->rightToLeft) { - if (falseBlock) - falseBlock->traverse(it); - if (trueBlock) - trueBlock->traverse(it); - condition->traverse(it); - } else { - condition->traverse(it); - if (trueBlock) - trueBlock->traverse(it); - if (falseBlock) - falseBlock->traverse(it); + if (it->rightToLeft) + { + if (mFalseBlock) + mFalseBlock->traverse(it); + if (mTrueBlock) + mTrueBlock->traverse(it); + mCondition->traverse(it); + } + else + { + mCondition->traverse(it); + if (mTrueBlock) + mTrueBlock->traverse(it); + if (mFalseBlock) + mFalseBlock->traverse(it); } it->decrementDepth(); } @@ -196,38 +202,38 @@ void TIntermLoop::traverse(TIntermTraverser *it) if (it->preVisit) visit = it->visitLoop(PreVisit, this); - + if (visit) { it->incrementDepth(this); if (it->rightToLeft) { - if (expr) - expr->traverse(it); + if (mExpr) + mExpr->traverse(it); - if (body) - body->traverse(it); + if (mBody) + mBody->traverse(it); - if (cond) - cond->traverse(it); + if (mCond) + mCond->traverse(it); - if (init) - init->traverse(it); + if (mInit) + mInit->traverse(it); } else { - if (init) - init->traverse(it); + if (mInit) + mInit->traverse(it); - if (cond) - cond->traverse(it); + if (mCond) + mCond->traverse(it); - if (body) - body->traverse(it); + if (mBody) + mBody->traverse(it); - if (expr) - expr->traverse(it); + if (mExpr) + mExpr->traverse(it); } it->decrementDepth(); @@ -246,10 +252,10 @@ void TIntermBranch::traverse(TIntermTraverser *it) if (it->preVisit) visit = it->visitBranch(PreVisit, this); - - if (visit && expression) { + + if (visit && mExpression) { it->incrementDepth(this); - expression->traverse(it); + mExpression->traverse(it); it->decrementDepth(); } @@ -257,3 +263,7 @@ void TIntermBranch::traverse(TIntermTraverser *it) it->visitBranch(PostVisit, this); } +void TIntermRaw::traverse(TIntermTraverser *it) +{ + it->visitRaw(this); +} diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp index 777cab5458..fa0c9f7748 100644 --- a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -16,110 +16,118 @@ #include "compiler/translator/localintermediate.h" #include "compiler/translator/QualifierAlive.h" #include "compiler/translator/RemoveTree.h" +#include "compiler/translator/SymbolTable.h" -bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray); +namespace +{ -static TPrecision GetHigherPrecision(TPrecision left, TPrecision right) +TPrecision GetHigherPrecision(TPrecision left, TPrecision right) { return left > right ? left : right; } -const char* getOperatorString(TOperator op) +bool ValidateMultiplication(TOperator op, const TType &left, const TType &right) { - switch (op) { - case EOpInitialize: return "="; - case EOpAssign: return "="; - case EOpAddAssign: return "+="; - case EOpSubAssign: return "-="; - case EOpDivAssign: return "/="; - - // Fall-through. - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: return "*="; - - // Fall-through. - case EOpIndexDirect: - case EOpIndexIndirect: return "[]"; - - case EOpIndexDirectStruct: return "."; - case EOpVectorSwizzle: return "."; - case EOpAdd: return "+"; - case EOpSub: return "-"; - case EOpMul: return "*"; - case EOpDiv: return "/"; - case EOpMod: UNIMPLEMENTED(); break; - case EOpEqual: return "=="; - case EOpNotEqual: return "!="; - case EOpLessThan: return "<"; - case EOpGreaterThan: return ">"; - case EOpLessThanEqual: return "<="; - case EOpGreaterThanEqual: return ">="; - - // Fall-through. + switch (op) + { + case EOpMul: + case EOpMulAssign: + return left.getNominalSize() == right.getNominalSize() && + left.getSecondarySize() == right.getSecondarySize(); case EOpVectorTimesScalar: + case EOpVectorTimesScalarAssign: + return true; case EOpVectorTimesMatrix: + return left.getNominalSize() == right.getRows(); + case EOpVectorTimesMatrixAssign: + return left.getNominalSize() == right.getRows() && + left.getNominalSize() == right.getCols(); case EOpMatrixTimesVector: + return left.getCols() == right.getNominalSize(); case EOpMatrixTimesScalar: - case EOpMatrixTimesMatrix: return "*"; - - case EOpLogicalOr: return "||"; - case EOpLogicalXor: return "^^"; - case EOpLogicalAnd: return "&&"; - case EOpNegative: return "-"; - case EOpVectorLogicalNot: return "not"; - case EOpLogicalNot: return "!"; - case EOpPostIncrement: return "++"; - case EOpPostDecrement: return "--"; - case EOpPreIncrement: return "++"; - case EOpPreDecrement: return "--"; - - // Fall-through. - case EOpConvIntToBool: - case EOpConvFloatToBool: return "bool"; - - // Fall-through. - case EOpConvBoolToFloat: - case EOpConvIntToFloat: return "float"; - - // Fall-through. - case EOpConvFloatToInt: - case EOpConvBoolToInt: return "int"; - - case EOpRadians: return "radians"; - case EOpDegrees: return "degrees"; - case EOpSin: return "sin"; - case EOpCos: return "cos"; - case EOpTan: return "tan"; - case EOpAsin: return "asin"; - case EOpAcos: return "acos"; - case EOpAtan: return "atan"; - case EOpExp: return "exp"; - case EOpLog: return "log"; - case EOpExp2: return "exp2"; - case EOpLog2: return "log2"; - case EOpSqrt: return "sqrt"; - case EOpInverseSqrt: return "inversesqrt"; - case EOpAbs: return "abs"; - case EOpSign: return "sign"; - case EOpFloor: return "floor"; - case EOpCeil: return "ceil"; - case EOpFract: return "fract"; - case EOpLength: return "length"; - case EOpNormalize: return "normalize"; - case EOpDFdx: return "dFdx"; - case EOpDFdy: return "dFdy"; - case EOpFwidth: return "fwidth"; - case EOpAny: return "any"; - case EOpAll: return "all"; - - default: break; + case EOpMatrixTimesScalarAssign: + return true; + case EOpMatrixTimesMatrix: + return left.getCols() == right.getRows(); + case EOpMatrixTimesMatrixAssign: + return left.getCols() == right.getCols() && + left.getRows() == right.getRows(); + + default: + UNREACHABLE(); + return false; + } +} + +bool CompareStructure(const TType& leftNodeType, + ConstantUnion *rightUnionArray, + ConstantUnion *leftUnionArray); + +bool CompareStruct(const TType &leftNodeType, + ConstantUnion *rightUnionArray, + ConstantUnion *leftUnionArray) +{ + const TFieldList &fields = leftNodeType.getStruct()->fields(); + + size_t structSize = fields.size(); + size_t index = 0; + + for (size_t j = 0; j < structSize; j++) + { + size_t size = fields[j]->type()->getObjectSize(); + for (size_t i = 0; i < size; i++) + { + if (fields[j]->type()->getBasicType() == EbtStruct) + { + if (!CompareStructure(*fields[j]->type(), + &rightUnionArray[index], + &leftUnionArray[index])) + { + return false; + } + } + else + { + if (leftUnionArray[index] != rightUnionArray[index]) + return false; + index++; + } + } } - return ""; + return true; } +bool CompareStructure(const TType &leftNodeType, + ConstantUnion *rightUnionArray, + ConstantUnion *leftUnionArray) +{ + if (leftNodeType.isArray()) + { + TType typeWithoutArrayness = leftNodeType; + typeWithoutArrayness.clearArrayness(); + + size_t arraySize = leftNodeType.getArraySize(); + + for (size_t i = 0; i < arraySize; ++i) + { + size_t offset = typeWithoutArrayness.getObjectSize() * i; + if (!CompareStruct(typeWithoutArrayness, + &rightUnionArray[offset], + &leftUnionArray[offset])) + { + return false; + } + } + } + else + { + return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); + } + return true; +} + +} // namespace anonymous + //////////////////////////////////////////////////////////////////////////// // // First set of functions are to help build the intermediate representation. @@ -133,9 +141,10 @@ const char* getOperatorString(TOperator op) // // Returns the added node. // -TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line) +TIntermSymbol *TIntermediate::addSymbol( + int id, const TString &name, const TType &type, const TSourceLoc &line) { - TIntermSymbol* node = new TIntermSymbol(id, name, type); + TIntermSymbol *node = new TIntermSymbol(id, name, type); node->setLine(line); return node; @@ -146,77 +155,71 @@ TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType // // Returns the added node. // -TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line, TSymbolTable& symbolTable) +TIntermTyped *TIntermediate::addBinaryMath( + TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) { - switch (op) { - case EOpEqual: - case EOpNotEqual: - if (left->isArray()) - return 0; - break; - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { - return 0; - } - break; - case EOpLogicalOr: - case EOpLogicalXor: - case EOpLogicalAnd: - if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { - return 0; - } - break; - case EOpAdd: - case EOpSub: - case EOpDiv: - case EOpMul: - if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) - return 0; - default: break; + switch (op) + { + case EOpEqual: + case EOpNotEqual: + if (left->isArray()) + return NULL; + break; + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (left->isMatrix() || left->isArray() || left->isVector() || + left->getBasicType() == EbtStruct) + { + return NULL; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + if (left->getBasicType() != EbtBool || + left->isMatrix() || left->isArray() || left->isVector()) + { + return NULL; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) + return NULL; + default: + break; } - // - // First try converting the children to compatible types. - // - if (left->getType().getStruct() && right->getType().getStruct()) { - if (left->getType() != right->getType()) - return 0; - } else { - TIntermTyped* child = addConversion(op, left->getType(), right); - if (child) - right = child; - else { - child = addConversion(op, right->getType(), left); - if (child) - left = child; - else - return 0; - } + if (left->getBasicType() != right->getBasicType()) + { + return NULL; } // // Need a new node holding things together then. Make // one and promote it to the right type. // - TIntermBinary* node = new TIntermBinary(op); + TIntermBinary *node = new TIntermBinary(op); node->setLine(line); node->setLeft(left); node->setRight(right); - if (!node->promote(infoSink)) - return 0; + if (!node->promote(mInfoSink)) + return NULL; // // See if we can fold constants. // - TIntermTyped* typedReturnNode = 0; TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); - if (leftTempConstant && rightTempConstant) { - typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); + if (leftTempConstant && rightTempConstant) + { + TIntermTyped *typedReturnNode = + leftTempConstant->fold(node->getOp(), rightTempConstant, mInfoSink); if (typedReturnNode) return typedReturnNode; @@ -230,23 +233,24 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn // // Returns the added node. // -TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) +TIntermTyped *TIntermediate::addAssign( + TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) { - // - // Like adding binary math, except the conversion can only go - // from right to left. - // - TIntermBinary* node = new TIntermBinary(op); - node->setLine(line); + if (left->getType().getStruct() || right->getType().getStruct()) + { + if (left->getType() != right->getType()) + { + return NULL; + } + } - TIntermTyped* child = addConversion(op, left->getType(), right); - if (child == 0) - return 0; + TIntermBinary *node = new TIntermBinary(op); + node->setLine(line); node->setLeft(left); - node->setRight(child); - if (! node->promote(infoSink)) - return 0; + node->setRight(right); + if (!node->promote(mInfoSink)) + return NULL; return node; } @@ -258,9 +262,10 @@ TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TInterm // Returns the added node. // The caller should set the type of the returned node. // -TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line) +TIntermTyped *TIntermediate::addIndex( + TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line) { - TIntermBinary* node = new TIntermBinary(op); + TIntermBinary *node = new TIntermBinary(op); node->setLine(line); node->setLeft(base); node->setRight(index); @@ -275,65 +280,43 @@ TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermT // // Returns the added node. // -TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable) +TIntermTyped *TIntermediate::addUnaryMath( + TOperator op, TIntermNode *childNode, const TSourceLoc &line) { - TIntermUnary* node; - TIntermTyped* child = childNode->getAsTyped(); - - if (child == 0) { - infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath"); - return 0; - } - - switch (op) { - case EOpLogicalNot: - if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { - return 0; - } - break; - - case EOpPostIncrement: - case EOpPreIncrement: - case EOpPostDecrement: - case EOpPreDecrement: - case EOpNegative: - if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) - return 0; - default: break; - } - - // - // Do we need to promote the operand? - // - // Note: Implicit promotions were removed from the language. - // - TBasicType newType = EbtVoid; - switch (op) { - case EOpConstructInt: newType = EbtInt; break; - case EOpConstructBool: newType = EbtBool; break; - case EOpConstructFloat: newType = EbtFloat; break; - default: break; - } + TIntermUnary *node; + TIntermTyped *child = childNode->getAsTyped(); - if (newType != EbtVoid) { - child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary, - child->getNominalSize(), - child->isMatrix(), - child->isArray()), - child); - if (child == 0) - return 0; + if (child == NULL) + { + mInfoSink.info.message(EPrefixInternalError, line, + "Bad type in AddUnaryMath"); + return NULL; } - // - // For constructors, we are now done, it's all in the conversion. - // - switch (op) { - case EOpConstructInt: - case EOpConstructBool: - case EOpConstructFloat: - return child; - default: break; + switch (op) + { + case EOpLogicalNot: + if (child->getType().getBasicType() != EbtBool || + child->getType().isMatrix() || + child->getType().isArray() || + child->getType().isVector()) + { + return NULL; + } + break; + + case EOpPostIncrement: + case EOpPreIncrement: + case EOpPostDecrement: + case EOpPreDecrement: + case EOpNegative: + if (child->getType().getBasicType() == EbtStruct || + child->getType().isArray()) + { + return NULL; + } + default: + break; } TIntermConstantUnion *childTempConstant = 0; @@ -347,11 +330,12 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, node->setLine(line); node->setOperand(child); - if (! node->promote(infoSink)) + if (!node->promote(mInfoSink)) return 0; - if (childTempConstant) { - TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); + if (childTempConstant) + { + TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink); if (newChild) return newChild; @@ -370,24 +354,30 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, // Returns an aggregate node, which could be the one passed in if // it was already an aggregate but no operator was set. // -TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line) +TIntermAggregate *TIntermediate::setAggregateOperator( + TIntermNode *node, TOperator op, const TSourceLoc &line) { - TIntermAggregate* aggNode; + TIntermAggregate *aggNode; // // Make sure we have an aggregate. If not turn it into one. // - if (node) { + if (node) + { aggNode = node->getAsAggregate(); - if (aggNode == 0 || aggNode->getOp() != EOpNull) { + if (aggNode == NULL || aggNode->getOp() != EOpNull) + { // // Make an aggregate containing this node. // aggNode = new TIntermAggregate(); - aggNode->getSequence().push_back(node); + aggNode->getSequence()->push_back(node); } - } else + } + else + { aggNode = new TIntermAggregate(); + } // // Set the operator. @@ -398,126 +388,6 @@ TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperat return aggNode; } -// -// Convert one type to another. -// -// Returns the node representing the conversion, which could be the same -// node passed in if no conversion was needed. -// -// Return 0 if a conversion can't be done. -// -TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) -{ - // - // Does the base type allow operation? - // - switch (node->getBasicType()) { - case EbtVoid: - case EbtSampler2D: - case EbtSamplerCube: - return 0; - default: break; - } - - // - // Otherwise, if types are identical, no problem - // - if (type == node->getType()) - return node; - - // - // If one's a structure, then no conversions. - // - if (type.getStruct() || node->getType().getStruct()) - return 0; - - // - // If one's an array, then no conversions. - // - if (type.isArray() || node->getType().isArray()) - return 0; - - TBasicType promoteTo; - - switch (op) { - // - // Explicit conversions - // - case EOpConstructBool: - promoteTo = EbtBool; - break; - case EOpConstructFloat: - promoteTo = EbtFloat; - break; - case EOpConstructInt: - promoteTo = EbtInt; - break; - default: - // - // implicit conversions were removed from the language. - // - if (type.getBasicType() != node->getType().getBasicType()) - return 0; - // - // Size and structure could still differ, but that's - // handled by operator promotion. - // - return node; - } - - if (node->getAsConstantUnion()) { - - return (promoteConstantUnion(promoteTo, node->getAsConstantUnion())); - } else { - - // - // Add a new newNode for the conversion. - // - TIntermUnary* newNode = 0; - - TOperator newOp = EOpNull; - switch (promoteTo) { - case EbtFloat: - switch (node->getBasicType()) { - case EbtInt: newOp = EOpConvIntToFloat; break; - case EbtBool: newOp = EOpConvBoolToFloat; break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); - return 0; - } - break; - case EbtBool: - switch (node->getBasicType()) { - case EbtInt: newOp = EOpConvIntToBool; break; - case EbtFloat: newOp = EOpConvFloatToBool; break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); - return 0; - } - break; - case EbtInt: - switch (node->getBasicType()) { - case EbtBool: newOp = EOpConvBoolToInt; break; - case EbtFloat: newOp = EOpConvFloatToInt; break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); - return 0; - } - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type"); - return 0; - } - - TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray()); - newNode = new TIntermUnary(newOp, type); - newNode->setLine(node->getLine()); - newNode->setOperand(node); - - return newNode; - } -} - // // Safe way to combine two nodes into an aggregate. Works with null pointers, // a node that's not a aggregate yet, etc. @@ -525,22 +395,24 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt // Returns the resulting aggregate, unless 0 was passed in for // both existing nodes. // -TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line) +TIntermAggregate *TIntermediate::growAggregate( + TIntermNode *left, TIntermNode *right, const TSourceLoc &line) { - if (left == 0 && right == 0) - return 0; + if (left == NULL && right == NULL) + return NULL; - TIntermAggregate* aggNode = 0; + TIntermAggregate *aggNode = NULL; if (left) aggNode = left->getAsAggregate(); - if (!aggNode || aggNode->getOp() != EOpNull) { + if (!aggNode || aggNode->getOp() != EOpNull) + { aggNode = new TIntermAggregate; if (left) - aggNode->getSequence().push_back(left); + aggNode->getSequence()->push_back(left); } if (right) - aggNode->getSequence().push_back(right); + aggNode->getSequence()->push_back(right); aggNode->setLine(line); @@ -550,15 +422,17 @@ TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* r // // Turn an existing node into an aggregate. // -// Returns an aggregate, unless 0 was passed in for the existing node. +// Returns an aggregate, unless NULL was passed in for the existing node. // -TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line) +TIntermAggregate *TIntermediate::makeAggregate( + TIntermNode *node, const TSourceLoc &line) { - if (node == 0) - return 0; + if (node == NULL) + return NULL; + + TIntermAggregate *aggNode = new TIntermAggregate; + aggNode->getSequence()->push_back(node); - TIntermAggregate* aggNode = new TIntermAggregate; - aggNode->getSequence().push_back(node); aggNode->setLine(line); return aggNode; @@ -571,32 +445,45 @@ TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceL // // Returns the selection node created. // -TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line) +TIntermNode *TIntermediate::addSelection( + TIntermTyped *cond, TIntermNodePair nodePair, const TSourceLoc &line) { // // For compile time constant selections, prune the code and // test now. // - if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { + if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) + { if (cond->getAsConstantUnion()->getBConst(0) == true) - return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; + { + return nodePair.node1 ? setAggregateOperator( + nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; + } else - return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; + { + return nodePair.node2 ? setAggregateOperator( + nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; + } } - TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); + TIntermSelection *node = new TIntermSelection( + cond, nodePair.node1, nodePair.node2); node->setLine(line); return node; } - -TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) +TIntermTyped *TIntermediate::addComma( + TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) { - if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) { + if (left->getType().getQualifier() == EvqConst && + right->getType().getQualifier() == EvqConst) + { return right; - } else { + } + else + { TIntermTyped *commaAggregate = growAggregate(left, right, line); commaAggregate->getAsAggregate()->setOp(EOpComma); commaAggregate->setType(right->getType()); @@ -612,27 +499,24 @@ TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, c // // Returns the selection node created, or 0 if one could not be. // -TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line) +TIntermTyped *TIntermediate::addSelection( + TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, + const TSourceLoc &line) { - // - // Get compatible types. - // - TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock); - if (child) - falseBlock = child; - else { - child = addConversion(EOpSequence, falseBlock->getType(), trueBlock); - if (child) - trueBlock = child; - else - return 0; + if (!cond || !trueBlock || !falseBlock || + trueBlock->getType() != falseBlock->getType()) + { + return NULL; } // // See if all the operands are constant, then fold it otherwise not. // - if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { + if (cond->getAsConstantUnion() && + trueBlock->getAsConstantUnion() && + falseBlock->getAsConstantUnion()) + { if (cond->getAsConstantUnion()->getBConst(0)) return trueBlock; else @@ -642,7 +526,8 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true // // Make a selection node. // - TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); + TIntermSelection *node = new TIntermSelection( + cond, trueBlock, falseBlock, trueBlock->getType()); node->getTypePointer()->setQualifier(EvqTemporary); node->setLine(line); @@ -655,29 +540,33 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true // Returns the constant union node created. // -TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line) +TIntermConstantUnion *TIntermediate::addConstantUnion( + ConstantUnion *unionArrayPointer, const TType &t, const TSourceLoc &line) { - TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); + TIntermConstantUnion *node = new TIntermConstantUnion(unionArrayPointer, t); node->setLine(line); return node; } -TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line) +TIntermTyped *TIntermediate::addSwizzle( + TVectorFields &fields, const TSourceLoc &line) { - TIntermAggregate* node = new TIntermAggregate(EOpSequence); + TIntermAggregate *node = new TIntermAggregate(EOpSequence); node->setLine(line); - TIntermConstantUnion* constIntNode; - TIntermSequence &sequenceVector = node->getSequence(); - ConstantUnion* unionArray; + TIntermConstantUnion *constIntNode; + TIntermSequence *sequenceVector = node->getSequence(); + ConstantUnion *unionArray; - for (int i = 0; i < fields.num; i++) { + for (int i = 0; i < fields.num; i++) + { unionArray = new ConstantUnion[1]; unionArray->setIConst(fields.offsets[i]); - constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); - sequenceVector.push_back(constIntNode); + constIntNode = addConstantUnion( + unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); + sequenceVector->push_back(constIntNode); } return node; @@ -686,9 +575,11 @@ TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& // // Create loop nodes. // -TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line) +TIntermNode *TIntermediate::addLoop( + TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr, + TIntermNode *body, const TSourceLoc &line) { - TIntermNode* node = new TIntermLoop(type, init, cond, expr, body); + TIntermNode *node = new TIntermLoop(type, init, cond, expr, body); node->setLine(line); return node; @@ -697,14 +588,16 @@ TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTy // // Add branches. // -TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line) +TIntermBranch* TIntermediate::addBranch( + TOperator branchOp, const TSourceLoc &line) { return addBranch(branchOp, 0, line); } -TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line) +TIntermBranch* TIntermediate::addBranch( + TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line) { - TIntermBranch* node = new TIntermBranch(branchOp, expression); + TIntermBranch *node = new TIntermBranch(branchOp, expression); node->setLine(line); return node; @@ -714,15 +607,15 @@ TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expres // This is to be executed once the final root is put on top by the parsing // process. // -bool TIntermediate::postProcess(TIntermNode* root) +bool TIntermediate::postProcess(TIntermNode *root) { - if (root == 0) + if (root == NULL) return true; // // First, finish off the top level sequence, if any // - TIntermAggregate* aggRoot = root->getAsAggregate(); + TIntermAggregate *aggRoot = root->getAsAggregate(); if (aggRoot && aggRoot->getOp() == EOpNull) aggRoot->setOp(EOpSequence); @@ -732,7 +625,7 @@ bool TIntermediate::postProcess(TIntermNode* root) // // This deletes the tree. // -void TIntermediate::remove(TIntermNode* root) +void TIntermediate::remove(TIntermNode *root) { if (root) RemoveAllTreeNodes(root); @@ -753,76 +646,149 @@ void TIntermediate::remove(TIntermNode* root) bool TIntermLoop::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(init, TIntermNode, original, replacement); - REPLACE_IF_IS(cond, TIntermTyped, original, replacement); - REPLACE_IF_IS(expr, TIntermTyped, original, replacement); - REPLACE_IF_IS(body, TIntermNode, original, replacement); + REPLACE_IF_IS(mInit, TIntermNode, original, replacement); + REPLACE_IF_IS(mCond, TIntermTyped, original, replacement); + REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement); + REPLACE_IF_IS(mBody, TIntermNode, original, replacement); return false; } +void TIntermLoop::enqueueChildren(std::queue *nodeQueue) const +{ + if (mInit) + { + nodeQueue->push(mInit); + } + if (mCond) + { + nodeQueue->push(mCond); + } + if (mExpr) + { + nodeQueue->push(mExpr); + } + if (mBody) + { + nodeQueue->push(mBody); + } +} + bool TIntermBranch::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(expression, TIntermTyped, original, replacement); + REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement); return false; } +void TIntermBranch::enqueueChildren(std::queue *nodeQueue) const +{ + if (mExpression) + { + nodeQueue->push(mExpression); + } +} + bool TIntermBinary::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(left, TIntermTyped, original, replacement); - REPLACE_IF_IS(right, TIntermTyped, original, replacement); + REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement); + REPLACE_IF_IS(mRight, TIntermTyped, original, replacement); return false; } +void TIntermBinary::enqueueChildren(std::queue *nodeQueue) const +{ + if (mLeft) + { + nodeQueue->push(mLeft); + } + if (mRight) + { + nodeQueue->push(mRight); + } +} + bool TIntermUnary::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(operand, TIntermTyped, original, replacement); + REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement); return false; } +void TIntermUnary::enqueueChildren(std::queue *nodeQueue) const +{ + if (mOperand) + { + nodeQueue->push(mOperand); + } +} + bool TIntermAggregate::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - for (size_t ii = 0; ii < sequence.size(); ++ii) + for (size_t ii = 0; ii < mSequence.size(); ++ii) { - REPLACE_IF_IS(sequence[ii], TIntermNode, original, replacement); + REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement); } return false; } +void TIntermAggregate::enqueueChildren(std::queue *nodeQueue) const +{ + for (size_t childIndex = 0; childIndex < mSequence.size(); childIndex++) + { + nodeQueue->push(mSequence[childIndex]); + } +} + bool TIntermSelection::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { - REPLACE_IF_IS(condition, TIntermTyped, original, replacement); - REPLACE_IF_IS(trueBlock, TIntermNode, original, replacement); - REPLACE_IF_IS(falseBlock, TIntermNode, original, replacement); + REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); + REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement); + REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement); return false; } +void TIntermSelection::enqueueChildren(std::queue *nodeQueue) const +{ + if (mCondition) + { + nodeQueue->push(mCondition); + } + if (mTrueBlock) + { + nodeQueue->push(mTrueBlock); + } + if (mFalseBlock) + { + nodeQueue->push(mFalseBlock); + } +} + // // Say whether or not an operation node changes the value of a variable. // bool TIntermOperator::isAssignment() const { - switch (op) { - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - case EOpAssign: - case EOpAddAssign: - case EOpSubAssign: - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: - case EOpDivAssign: - return true; - default: - return false; + switch (mOp) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + return true; + default: + return false; } } @@ -831,26 +797,31 @@ bool TIntermOperator::isAssignment() const // bool TIntermOperator::isConstructor() const { - switch (op) { - case EOpConstructVec2: - case EOpConstructVec3: - case EOpConstructVec4: - case EOpConstructMat2: - case EOpConstructMat3: - case EOpConstructMat4: - case EOpConstructFloat: - case EOpConstructIVec2: - case EOpConstructIVec3: - case EOpConstructIVec4: - case EOpConstructInt: - case EOpConstructBVec2: - case EOpConstructBVec3: - case EOpConstructBVec4: - case EOpConstructBool: - case EOpConstructStruct: - return true; - default: - return false; + switch (mOp) + { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + case EOpConstructUVec2: + case EOpConstructUVec3: + case EOpConstructUVec4: + case EOpConstructUInt: + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + case EOpConstructStruct: + return true; + default: + return false; } } @@ -860,35 +831,36 @@ bool TIntermOperator::isConstructor() const // // Returns false in nothing makes sense. // -bool TIntermUnary::promote(TInfoSink&) +bool TIntermUnary::promote(TInfoSink &) { - switch (op) { - case EOpLogicalNot: - if (operand->getBasicType() != EbtBool) - return false; - break; - case EOpNegative: - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - if (operand->getBasicType() == EbtBool) - return false; - break; + switch (mOp) + { + case EOpLogicalNot: + if (mOperand->getBasicType() != EbtBool) + return false; + break; + case EOpNegative: + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + if (mOperand->getBasicType() == EbtBool) + return false; + break; - // operators for built-ins are already type checked against their prototype - case EOpAny: - case EOpAll: - case EOpVectorLogicalNot: - return true; + // operators for built-ins are already type checked against their prototype + case EOpAny: + case EOpAll: + case EOpVectorLogicalNot: + return true; - default: - if (operand->getBasicType() != EbtFloat) - return false; + default: + if (mOperand->getBasicType() != EbtFloat) + return false; } - setType(operand->getType()); - type.setQualifier(EvqTemporary); + setType(mOperand->getType()); + mType.setQualifier(EvqTemporary); return true; } @@ -899,221 +871,260 @@ bool TIntermUnary::promote(TInfoSink&) // // Returns false if operator can't work on operands. // -bool TIntermBinary::promote(TInfoSink& infoSink) +bool TIntermBinary::promote(TInfoSink &infoSink) { // This function only handles scalars, vectors, and matrices. - if (left->isArray() || right->isArray()) { - infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays"); + if (mLeft->isArray() || mRight->isArray()) + { + infoSink.info.message(EPrefixInternalError, getLine(), + "Invalid operation for arrays"); return false; } // GLSL ES 2.0 does not support implicit type casting. // So the basic type should always match. - if (left->getBasicType() != right->getBasicType()) + if (mLeft->getBasicType() != mRight->getBasicType()) + { return false; + } // // Base assumption: just make the type the same as the left // operand. Then only deviations from this need be coded. // - setType(left->getType()); + setType(mLeft->getType()); // The result gets promoted to the highest precision. - TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); + TPrecision higherPrecision = GetHigherPrecision( + mLeft->getPrecision(), mRight->getPrecision()); getTypePointer()->setPrecision(higherPrecision); // Binary operations results in temporary variables unless both // operands are const. - if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) { + if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst) + { getTypePointer()->setQualifier(EvqTemporary); } - int size = std::max(left->getNominalSize(), right->getNominalSize()); + const int nominalSize = + std::max(mLeft->getNominalSize(), mRight->getNominalSize()); // - // All scalars. Code after this test assumes this case is removed! + // All scalars or structs. Code after this test assumes this case is removed! // - if (size == 1) { - switch (op) { - // - // Promote to conditional - // - case EOpEqual: - case EOpNotEqual: - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - setType(TType(EbtBool, EbpUndefined)); - break; + if (nominalSize == 1) + { + switch (mOp) + { + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + setType(TType(EbtBool, EbpUndefined)); + break; - // - // And and Or operate on conditionals - // - case EOpLogicalAnd: - case EOpLogicalOr: - // Both operands must be of type bool. - if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) - return false; - setType(TType(EbtBool, EbpUndefined)); - break; + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalOr: + // Both operands must be of type bool. + if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool) + { + return false; + } + setType(TType(EbtBool, EbpUndefined)); + break; - default: - break; + default: + break; } return true; } // If we reach here, at least one of the operands is vector or matrix. // The other operand could be a scalar, vector, or matrix. - // Are the sizes compatible? - // - if (left->getNominalSize() != right->getNominalSize()) { - // If the nominal size of operands do not match: - // One of them must be scalar. - if (left->getNominalSize() != 1 && right->getNominalSize() != 1) - return false; - // Operator cannot be of type pure assignment. - if (op == EOpAssign || op == EOpInitialize) - return false; - } - - // // Can these two operands be combined? // - TBasicType basicType = left->getBasicType(); - switch (op) { - case EOpMul: - if (!left->isMatrix() && right->isMatrix()) { - if (left->isVector()) - op = EOpVectorTimesMatrix; - else { - op = EOpMatrixTimesScalar; - setType(TType(basicType, higherPrecision, EvqTemporary, size, true)); - } - } else if (left->isMatrix() && !right->isMatrix()) { - if (right->isVector()) { - op = EOpMatrixTimesVector; - setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); - } else { - op = EOpMatrixTimesScalar; - } - } else if (left->isMatrix() && right->isMatrix()) { - op = EOpMatrixTimesMatrix; - } else if (!left->isMatrix() && !right->isMatrix()) { - if (left->isVector() && right->isVector()) { - // leave as component product - } else if (left->isVector() || right->isVector()) { - op = EOpVectorTimesScalar; - setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); - } - } else { - infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); - return false; + TBasicType basicType = mLeft->getBasicType(); + switch (mOp) + { + case EOpMul: + if (!mLeft->isMatrix() && mRight->isMatrix()) + { + if (mLeft->isVector()) + { + mOp = EOpVectorTimesMatrix; + setType(TType(basicType, higherPrecision, EvqTemporary, + mRight->getCols(), 1)); } - break; - case EOpMulAssign: - if (!left->isMatrix() && right->isMatrix()) { - if (left->isVector()) - op = EOpVectorTimesMatrixAssign; - else { - return false; - } - } else if (left->isMatrix() && !right->isMatrix()) { - if (right->isVector()) { - return false; - } else { - op = EOpMatrixTimesScalarAssign; - } - } else if (left->isMatrix() && right->isMatrix()) { - op = EOpMatrixTimesMatrixAssign; - } else if (!left->isMatrix() && !right->isMatrix()) { - if (left->isVector() && right->isVector()) { - // leave as component product - } else if (left->isVector() || right->isVector()) { - if (! left->isVector()) - return false; - op = EOpVectorTimesScalarAssign; - setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); - } - } else { - infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); - return false; + else + { + mOp = EOpMatrixTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, + mRight->getCols(), mRight->getRows())); } - break; + } + else if (mLeft->isMatrix() && !mRight->isMatrix()) + { + if (mRight->isVector()) + { + mOp = EOpMatrixTimesVector; + setType(TType(basicType, higherPrecision, EvqTemporary, + mLeft->getRows(), 1)); + } + else + { + mOp = EOpMatrixTimesScalar; + } + } + else if (mLeft->isMatrix() && mRight->isMatrix()) + { + mOp = EOpMatrixTimesMatrix; + setType(TType(basicType, higherPrecision, EvqTemporary, + mRight->getCols(), mLeft->getRows())); + } + else if (!mLeft->isMatrix() && !mRight->isMatrix()) + { + if (mLeft->isVector() && mRight->isVector()) + { + // leave as component product + } + else if (mLeft->isVector() || mRight->isVector()) + { + mOp = EOpVectorTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, + nominalSize, 1)); + } + } + else + { + infoSink.info.message(EPrefixInternalError, getLine(), + "Missing elses"); + return false; + } - case EOpAssign: - case EOpInitialize: - case EOpAdd: - case EOpSub: - case EOpDiv: - case EOpAddAssign: - case EOpSubAssign: - case EOpDivAssign: - if ((left->isMatrix() && right->isVector()) || - (left->isVector() && right->isMatrix())) + if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) + { + return false; + } + break; + + case EOpMulAssign: + if (!mLeft->isMatrix() && mRight->isMatrix()) + { + if (mLeft->isVector()) + { + mOp = EOpVectorTimesMatrixAssign; + } + else + { return false; - setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix())); - break; - - case EOpEqual: - case EOpNotEqual: - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - if ((left->isMatrix() && right->isVector()) || - (left->isVector() && right->isMatrix())) + } + } + else if (mLeft->isMatrix() && !mRight->isMatrix()) + { + if (mRight->isVector()) + { return false; - setType(TType(EbtBool, EbpUndefined)); - break; - - default: - return false; - } - - return true; -} - -bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) -{ - const TFieldList& fields = leftNodeType.getStruct()->fields(); - - size_t structSize = fields.size(); - size_t index = 0; - - for (size_t j = 0; j < structSize; j++) { - size_t size = fields[j]->type()->getObjectSize(); - for (size_t i = 0; i < size; i++) { - if (fields[j]->type()->getBasicType() == EbtStruct) { - if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index])) - return false; - } else { - if (leftUnionArray[index] != rightUnionArray[index]) + } + else + { + mOp = EOpMatrixTimesScalarAssign; + } + } + else if (mLeft->isMatrix() && mRight->isMatrix()) + { + mOp = EOpMatrixTimesMatrixAssign; + setType(TType(basicType, higherPrecision, EvqTemporary, + mRight->getCols(), mLeft->getRows())); + } + else if (!mLeft->isMatrix() && !mRight->isMatrix()) + { + if (mLeft->isVector() && mRight->isVector()) + { + // leave as component product + } + else if (mLeft->isVector() || mRight->isVector()) + { + if (!mLeft->isVector()) return false; - index++; + mOp = EOpVectorTimesScalarAssign; + setType(TType(basicType, higherPrecision, EvqTemporary, + mLeft->getNominalSize(), 1)); } } - } - return true; -} + else + { + infoSink.info.message(EPrefixInternalError, getLine(), + "Missing elses"); + return false; + } -bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) -{ - if (leftNodeType.isArray()) { - TType typeWithoutArrayness = leftNodeType; - typeWithoutArrayness.clearArrayness(); + if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) + { + return false; + } + break; + + case EOpAssign: + case EOpInitialize: + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + if ((mLeft->isMatrix() && mRight->isVector()) || + (mLeft->isVector() && mRight->isMatrix())) + { + return false; + } - size_t arraySize = leftNodeType.getArraySize(); + // Are the sizes compatible? + if (mLeft->getNominalSize() != mRight->getNominalSize() || + mLeft->getSecondarySize() != mRight->getSecondarySize()) + { + // If the nominal size of operands do not match: + // One of them must be scalar. + if (!mLeft->isScalar() && !mRight->isScalar()) + return false; - for (size_t i = 0; i < arraySize; ++i) { - size_t offset = typeWithoutArrayness.getObjectSize() * i; - if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset])) + // Operator cannot be of type pure assignment. + if (mOp == EOpAssign || mOp == EOpInitialize) return false; } - } else - return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); + { + const int secondarySize = std::max( + mLeft->getSecondarySize(), mRight->getSecondarySize()); + setType(TType(basicType, higherPrecision, EvqTemporary, + nominalSize, secondarySize)); + } + break; + + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if ((mLeft->getNominalSize() != mRight->getNominalSize()) || + (mLeft->getSecondarySize() != mRight->getSecondarySize())) + { + return false; + } + setType(TType(EbtBool, EbpUndefined)); + break; + + default: + return false; + } return true; } @@ -1123,372 +1134,472 @@ bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, // // Returns the node to keep using, which may or may not be the node passed in. // - -TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) +TIntermTyped *TIntermConstantUnion::fold( + TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink) { ConstantUnion *unionArray = getUnionArrayPointer(); + + if (!unionArray) + return NULL; + size_t objectSize = getType().getObjectSize(); - if (constantNode) { // binary operations + if (constantNode) + { + // binary operations TIntermConstantUnion *node = constantNode->getAsConstantUnion(); ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); TType returnType = getType(); + if (!rightUnionArray) + return NULL; + // for a case like float f = 1.2 + vec4(2,3,4,5); - if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { + if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) + { rightUnionArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; ++i) + { rightUnionArray[i] = *node->getUnionArrayPointer(); + } returnType = getType(); - } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { + } + else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) + { // for a case like float f = vec4(2,3,4,5) + 1.2; unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i) + { unionArray[i] = *getUnionArrayPointer(); + } returnType = node->getType(); objectSize = constantNode->getType().getObjectSize(); } - ConstantUnion* tempConstArray = 0; + ConstantUnion *tempConstArray = NULL; TIntermConstantUnion *tempNode; bool boolNodeFlag = false; - switch(op) { - case EOpAdd: - tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] + rightUnionArray[i]; - } - break; - case EOpSub: - tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] - rightUnionArray[i]; - } - break; + switch(op) + { + case EOpAdd: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] + rightUnionArray[i]; + break; + case EOpSub: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] - rightUnionArray[i]; + break; - case EOpMul: - case EOpVectorTimesScalar: - case EOpMatrixTimesScalar: - tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] * rightUnionArray[i]; - } - break; - case EOpMatrixTimesMatrix: - if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { - infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply"); - return 0; + case EOpMul: + case EOpVectorTimesScalar: + case EOpMatrixTimesScalar: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] * rightUnionArray[i]; + break; + + case EOpMatrixTimesMatrix: + { + if (getType().getBasicType() != EbtFloat || + node->getBasicType() != EbtFloat) + { + infoSink.info.message( + EPrefixInternalError, getLine(), + "Constant Folding cannot be done for matrix multiply"); + return NULL; } - {// support MSVC++6.0 - int size = getNominalSize(); - tempConstArray = new ConstantUnion[size*size]; - for (int row = 0; row < size; row++) { - for (int column = 0; column < size; column++) { - tempConstArray[size * column + row].setFConst(0.0f); - for (int i = 0; i < size; i++) { - tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst())); - } + + const int leftCols = getCols(); + const int leftRows = getRows(); + const int rightCols = constantNode->getType().getCols(); + const int rightRows = constantNode->getType().getRows(); + const int resultCols = rightCols; + const int resultRows = leftRows; + + tempConstArray = new ConstantUnion[resultCols*resultRows]; + for (int row = 0; row < resultRows; row++) + { + for (int column = 0; column < resultCols; column++) + { + tempConstArray[resultRows * column + row].setFConst(0.0f); + for (int i = 0; i < leftCols; i++) + { + tempConstArray[resultRows * column + row].setFConst( + tempConstArray[resultRows * column + row].getFConst() + + unionArray[i * leftRows + row].getFConst() * + rightUnionArray[column * rightRows + i].getFConst()); } } } - break; - case EOpDiv: + + // update return type for matrix product + returnType.setPrimarySize(resultCols); + returnType.setSecondarySize(resultRows); + } + break; + + case EOpDiv: + { tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) { - switch (getType().getBasicType()) { - case EbtFloat: - if (rightUnionArray[i] == 0.0f) { - infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); - tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); - } else - tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); - break; + for (size_t i = 0; i < objectSize; i++) + { + switch (getType().getBasicType()) + { + case EbtFloat: + if (rightUnionArray[i] == 0.0f) + { + infoSink.info.message( + EPrefixWarning, getLine(), + "Divide by zero error during constant folding"); + tempConstArray[i].setFConst( + unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); + } + else + { + tempConstArray[i].setFConst( + unionArray[i].getFConst() / + rightUnionArray[i].getFConst()); + } + break; - case EbtInt: - if (rightUnionArray[i] == 0) { - infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); - tempConstArray[i].setIConst(INT_MAX); - } else - tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); - break; - default: - infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\""); - return 0; + case EbtInt: + if (rightUnionArray[i] == 0) + { + infoSink.info.message( + EPrefixWarning, getLine(), + "Divide by zero error during constant folding"); + tempConstArray[i].setIConst(INT_MAX); + } + else + { + tempConstArray[i].setIConst( + unionArray[i].getIConst() / + rightUnionArray[i].getIConst()); + } + break; + + case EbtUInt: + if (rightUnionArray[i] == 0) + { + infoSink.info.message( + EPrefixWarning, getLine(), + "Divide by zero error during constant folding"); + tempConstArray[i].setUConst(UINT_MAX); + } + else + { + tempConstArray[i].setUConst( + unionArray[i].getUConst() / + rightUnionArray[i].getUConst()); } + break; + + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Constant folding cannot be done for \"/\""); + return NULL; } } - break; + } + break; - case EOpMatrixTimesVector: - if (node->getBasicType() != EbtFloat) { - infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector"); - return 0; + case EOpMatrixTimesVector: + { + if (node->getBasicType() != EbtFloat) + { + infoSink.info.message( + EPrefixInternalError, getLine(), + "Constant Folding cannot be done for matrix times vector"); + return NULL; } - tempConstArray = new ConstantUnion[getNominalSize()]; - {// support MSVC++6.0 - for (int size = getNominalSize(), i = 0; i < size; i++) { - tempConstArray[i].setFConst(0.0f); - for (int j = 0; j < size; j++) { - tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst())); - } + const int matrixCols = getCols(); + const int matrixRows = getRows(); + + tempConstArray = new ConstantUnion[matrixRows]; + + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + { + tempConstArray[matrixRow].setFConst(0.0f); + for (int col = 0; col < matrixCols; col++) + { + tempConstArray[matrixRow].setFConst( + tempConstArray[matrixRow].getFConst() + + unionArray[col * matrixRows + matrixRow].getFConst() * + rightUnionArray[col].getFConst()); } } - tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); + returnType = node->getType(); + returnType.setPrimarySize(matrixRows); + + tempNode = new TIntermConstantUnion(tempConstArray, returnType); tempNode->setLine(getLine()); return tempNode; + } - case EOpVectorTimesMatrix: - if (getType().getBasicType() != EbtFloat) { - infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix"); - return 0; + case EOpVectorTimesMatrix: + { + if (getType().getBasicType() != EbtFloat) + { + infoSink.info.message( + EPrefixInternalError, getLine(), + "Constant Folding cannot be done for vector times matrix"); + return NULL; } - tempConstArray = new ConstantUnion[getNominalSize()]; - {// support MSVC++6.0 - for (int size = getNominalSize(), i = 0; i < size; i++) { - tempConstArray[i].setFConst(0.0f); - for (int j = 0; j < size; j++) { - tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst())); - } + const int matrixCols = constantNode->getType().getCols(); + const int matrixRows = constantNode->getType().getRows(); + + tempConstArray = new ConstantUnion[matrixCols]; + + for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++) + { + tempConstArray[matrixCol].setFConst(0.0f); + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + { + tempConstArray[matrixCol].setFConst( + tempConstArray[matrixCol].getFConst() + + unionArray[matrixRow].getFConst() * + rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst()); } } - break; - case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently + returnType.setPrimarySize(matrixCols); + } + break; + + case EOpLogicalAnd: + // this code is written for possible future use, + // will not get executed currently + { tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] && rightUnionArray[i]; + for (size_t i = 0; i < objectSize; i++) + { + tempConstArray[i] = unionArray[i] && rightUnionArray[i]; } - break; + } + break; - case EOpLogicalOr: // this code is written for possible future use, will not get executed currently + case EOpLogicalOr: + // this code is written for possible future use, + // will not get executed currently + { tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] || rightUnionArray[i]; + for (size_t i = 0; i < objectSize; i++) + { + tempConstArray[i] = unionArray[i] || rightUnionArray[i]; } - break; + } + break; - case EOpLogicalXor: + case EOpLogicalXor: + { tempConstArray = new ConstantUnion[objectSize]; - {// support MSVC++6.0 - for (size_t i = 0; i < objectSize; i++) - switch (getType().getBasicType()) { - case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; - default: assert(false && "Default missing"); + for (size_t i = 0; i < objectSize; i++) + { + switch (getType().getBasicType()) + { + case EbtBool: + tempConstArray[i].setBConst( + unionArray[i] == rightUnionArray[i] ? false : true); + break; + default: + UNREACHABLE(); + break; } } - break; + } + break; + + case EOpLessThan: + ASSERT(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray < *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; - case EOpLessThan: - assert(objectSize == 1); + case EOpGreaterThan: + ASSERT(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray > *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + + case EOpLessThanEqual: + { + ASSERT(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray > *rightUnionArray); tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(*unionArray < *rightUnionArray); + tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; - case EOpGreaterThan: - assert(objectSize == 1); + } + + case EOpGreaterThanEqual: + { + ASSERT(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray < *rightUnionArray); tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(*unionArray > *rightUnionArray); + tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; - case EOpLessThanEqual: + } + + case EOpEqual: + if (getType().getBasicType() == EbtStruct) + { + if (!CompareStructure(node->getType(), + node->getUnionArrayPointer(), + unionArray)) { - assert(objectSize == 1); - ConstantUnion constant; - constant.setBConst(*unionArray > *rightUnionArray); - tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(!constant.getBConst()); - returnType = TType(EbtBool, EbpUndefined, EvqConst); - break; + boolNodeFlag = true; } - case EOpGreaterThanEqual: + } + else + { + for (size_t i = 0; i < objectSize; i++) { - assert(objectSize == 1); - ConstantUnion constant; - constant.setBConst(*unionArray < *rightUnionArray); - tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(!constant.getBConst()); - returnType = TType(EbtBool, EbpUndefined, EvqConst); - break; - } - - case EOpEqual: - if (getType().getBasicType() == EbtStruct) { - if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + if (unionArray[i] != rightUnionArray[i]) + { boolNodeFlag = true; - } else { - for (size_t i = 0; i < objectSize; i++) { - if (unionArray[i] != rightUnionArray[i]) { - boolNodeFlag = true; - break; // break out of for loop - } + break; // break out of for loop } } + } - tempConstArray = new ConstantUnion[1]; - if (!boolNodeFlag) { - tempConstArray->setBConst(true); - } - else { - tempConstArray->setBConst(false); - } + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) + { + tempConstArray->setBConst(true); + } + else + { + tempConstArray->setBConst(false); + } - tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); - tempNode->setLine(getLine()); + tempNode = new TIntermConstantUnion( + tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); - return tempNode; + return tempNode; - case EOpNotEqual: - if (getType().getBasicType() == EbtStruct) { - if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + case EOpNotEqual: + if (getType().getBasicType() == EbtStruct) + { + if (CompareStructure(node->getType(), + node->getUnionArrayPointer(), + unionArray)) + { + boolNodeFlag = true; + } + } + else + { + for (size_t i = 0; i < objectSize; i++) + { + if (unionArray[i] == rightUnionArray[i]) + { boolNodeFlag = true; - } else { - for (size_t i = 0; i < objectSize; i++) { - if (unionArray[i] == rightUnionArray[i]) { - boolNodeFlag = true; - break; // break out of for loop - } + break; // break out of for loop } } + } - tempConstArray = new ConstantUnion[1]; - if (!boolNodeFlag) { - tempConstArray->setBConst(true); - } - else { - tempConstArray->setBConst(false); - } + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) + { + tempConstArray->setBConst(true); + } + else + { + tempConstArray->setBConst(false); + } - tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); - tempNode->setLine(getLine()); + tempNode = new TIntermConstantUnion( + tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); - return tempNode; + return tempNode; - default: - infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding"); - return 0; + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Invalid operator for constant folding"); + return NULL; } tempNode = new TIntermConstantUnion(tempConstArray, returnType); tempNode->setLine(getLine()); return tempNode; - } else { + } + else + { // // Do unary operations // TIntermConstantUnion *newNode = 0; ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) { - switch(op) { - case EOpNegative: - switch (getType().getBasicType()) { - case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; - case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; - default: - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return 0; - } + for (size_t i = 0; i < objectSize; i++) + { + switch(op) + { + case EOpNegative: + switch (getType().getBasicType()) + { + case EbtFloat: + tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; - case EOpLogicalNot: // this code is written for possible future use, will not get executed currently - switch (getType().getBasicType()) { - case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; - default: - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return 0; - } + case EbtInt: + tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; - default: - return 0; - } - } - newNode = new TIntermConstantUnion(tempConstArray, getType()); - newNode->setLine(getLine()); - return newNode; - } -} - -TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) -{ - size_t size = node->getType().getObjectSize(); - - ConstantUnion *leftUnionArray = new ConstantUnion[size]; - - for (size_t i = 0; i < size; i++) { - - switch (promoteTo) { - case EbtFloat: - switch (node->getType().getBasicType()) { - case EbtInt: - leftUnionArray[i].setFConst(static_cast(node->getIConst(i))); - break; - case EbtBool: - leftUnionArray[i].setFConst(static_cast(node->getBConst(i))); - break; - case EbtFloat: - leftUnionArray[i].setFConst(static_cast(node->getFConst(i))); - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); - return 0; + case EbtUInt: + tempConstArray[i].setUConst(static_cast( + -static_cast(unionArray[i].getUConst()))); + break; + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Unary operation not folded into constant"); + return NULL; } break; - case EbtInt: - switch (node->getType().getBasicType()) { - case EbtInt: - leftUnionArray[i].setIConst(static_cast(node->getIConst(i))); - break; - case EbtBool: - leftUnionArray[i].setIConst(static_cast(node->getBConst(i))); - break; - case EbtFloat: - leftUnionArray[i].setIConst(static_cast(node->getFConst(i))); - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); - return 0; + + case EOpLogicalNot: + // this code is written for possible future use, + // will not get executed currently + switch (getType().getBasicType()) + { + case EbtBool: + tempConstArray[i].setBConst(!unionArray[i].getBConst()); + break; + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Unary operation not folded into constant"); + return NULL; } break; - case EbtBool: - switch (node->getType().getBasicType()) { - case EbtInt: - leftUnionArray[i].setBConst(node->getIConst(i) != 0); - break; - case EbtBool: - leftUnionArray[i].setBConst(node->getBConst(i)); - break; - case EbtFloat: - leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f); - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); - return 0; - } - break; - default: - infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found"); - return 0; + default: + return NULL; + } } - + newNode = new TIntermConstantUnion(tempConstArray, getType()); + newNode->setLine(getLine()); + return newNode; } - - const TType& t = node->getType(); - - return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); } // static -TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction) +TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction) { if (hashFunction == NULL || name.empty()) return name; diff --git a/src/3rdparty/angle/src/compiler/translator/LoopInfo.cpp b/src/3rdparty/angle/src/compiler/translator/LoopInfo.cpp new file mode 100644 index 0000000000..d931a18a23 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/LoopInfo.cpp @@ -0,0 +1,211 @@ +// +// Copyright (c) 2002-2014 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/LoopInfo.h" + +namespace +{ + +int EvaluateIntConstant(TIntermConstantUnion *node) +{ + ASSERT(node && node->getUnionArrayPointer()); + return node->getIConst(0); +} + +int GetLoopIntIncrement(TIntermLoop *node) +{ + TIntermNode *expr = node->getExpression(); + // for expression has one of the following forms: + // loop_index++ + // loop_index-- + // loop_index += constant_expression + // loop_index -= constant_expression + // ++loop_index + // --loop_index + // The last two forms are not specified in the spec, but I am assuming + // its an oversight. + TIntermUnary *unOp = expr->getAsUnaryNode(); + TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode(); + + TOperator op = EOpNull; + TIntermConstantUnion *incrementNode = NULL; + if (unOp) + { + op = unOp->getOp(); + } + else if (binOp) + { + op = binOp->getOp(); + ASSERT(binOp->getRight()); + incrementNode = binOp->getRight()->getAsConstantUnion(); + ASSERT(incrementNode); + } + + int increment = 0; + // The operator is one of: ++ -- += -=. + switch (op) + { + case EOpPostIncrement: + case EOpPreIncrement: + ASSERT(unOp && !binOp); + increment = 1; + break; + case EOpPostDecrement: + case EOpPreDecrement: + ASSERT(unOp && !binOp); + increment = -1; + break; + case EOpAddAssign: + ASSERT(!unOp && binOp); + increment = EvaluateIntConstant(incrementNode); + break; + case EOpSubAssign: + ASSERT(!unOp && binOp); + increment = - EvaluateIntConstant(incrementNode); + break; + default: + UNREACHABLE(); + } + + return increment; +} + +} // namespace anonymous + +TLoopIndexInfo::TLoopIndexInfo() + : mId(-1), + mType(EbtVoid), + mInitValue(0), + mStopValue(0), + mIncrementValue(0), + mOp(EOpNull), + mCurrentValue(0) +{ +} + +void TLoopIndexInfo::fillInfo(TIntermLoop *node) +{ + if (node == NULL) + return; + + // Here we assume all the operations are valid, because the loop node is + // already validated in ValidateLimitations. + TIntermSequence *declSeq = + node->getInit()->getAsAggregate()->getSequence(); + TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode(); + TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); + + mId = symbol->getId(); + mType = symbol->getBasicType(); + + if (mType == EbtInt) + { + TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion(); + mInitValue = EvaluateIntConstant(initNode); + mCurrentValue = mInitValue; + mIncrementValue = GetLoopIntIncrement(node); + + TIntermBinary* binOp = node->getCondition()->getAsBinaryNode(); + mStopValue = EvaluateIntConstant( + binOp->getRight()->getAsConstantUnion()); + mOp = binOp->getOp(); + } +} + +bool TLoopIndexInfo::satisfiesLoopCondition() const +{ + // Relational operator is one of: > >= < <= == or !=. + switch (mOp) + { + case EOpEqual: + return (mCurrentValue == mStopValue); + case EOpNotEqual: + return (mCurrentValue != mStopValue); + case EOpLessThan: + return (mCurrentValue < mStopValue); + case EOpGreaterThan: + return (mCurrentValue > mStopValue); + case EOpLessThanEqual: + return (mCurrentValue <= mStopValue); + case EOpGreaterThanEqual: + return (mCurrentValue >= mStopValue); + default: + UNREACHABLE(); + return false; + } +} + +TLoopInfo::TLoopInfo() + : loop(NULL) +{ +} + +TLoopInfo::TLoopInfo(TIntermLoop *node) + : loop(node) +{ + index.fillInfo(node); +} + +TIntermLoop *TLoopStack::findLoop(TIntermSymbol *symbol) +{ + if (!symbol) + return NULL; + for (iterator iter = begin(); iter != end(); ++iter) + { + if (iter->index.getId() == symbol->getId()) + return iter->loop; + } + return NULL; +} + +TLoopIndexInfo *TLoopStack::getIndexInfo(TIntermSymbol *symbol) +{ + if (!symbol) + return NULL; + for (iterator iter = begin(); iter != end(); ++iter) + { + if (iter->index.getId() == symbol->getId()) + return &(iter->index); + } + return NULL; +} + +void TLoopStack::step() +{ + ASSERT(!empty()); + rbegin()->index.step(); +} + +bool TLoopStack::satisfiesLoopCondition() +{ + ASSERT(!empty()); + return rbegin()->index.satisfiesLoopCondition(); +} + +bool TLoopStack::needsToReplaceSymbolWithValue(TIntermSymbol *symbol) +{ + TIntermLoop *loop = findLoop(symbol); + return loop && loop->getUnrollFlag(); +} + +int TLoopStack::getLoopIndexValue(TIntermSymbol *symbol) +{ + TLoopIndexInfo *info = getIndexInfo(symbol); + ASSERT(info); + return info->getCurrentValue(); +} + +void TLoopStack::push(TIntermLoop *loop) +{ + TLoopInfo info(loop); + push_back(info); +} + +void TLoopStack::pop() +{ + pop_back(); +} + diff --git a/src/3rdparty/angle/src/compiler/translator/LoopInfo.h b/src/3rdparty/angle/src/compiler/translator/LoopInfo.h new file mode 100644 index 0000000000..5a140c339e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/LoopInfo.h @@ -0,0 +1,80 @@ +// +// Copyright (c) 2002-2014 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. +// + +#ifndef COMPILER_TRANSLATOR_LOOP_INFO_H_ +#define COMPILER_TRANSLATOR_LOOP_INFO_H_ + +#include "compiler/translator/intermediate.h" + +class TLoopIndexInfo +{ + public: + TLoopIndexInfo(); + + // If type is EbtInt, fill all fields of the structure with info + // extracted from a loop node. + // If type is not EbtInt, only fill id and type. + void fillInfo(TIntermLoop *node); + + int getId() const { return mId; } + void setId(int id) { mId = id; } + TBasicType getType() const { return mType; } + void setType(TBasicType type) { mType = type; } + int getCurrentValue() const { return mCurrentValue; } + + void step() { mCurrentValue += mIncrementValue; } + + // Check if the current value satisfies the loop condition. + bool satisfiesLoopCondition() const; + + private: + int mId; + TBasicType mType; // Either EbtInt or EbtFloat + + // Below fields are only valid if the index's type is int. + int mInitValue; + int mStopValue; + int mIncrementValue; + TOperator mOp; + int mCurrentValue; +}; + +struct TLoopInfo +{ + TLoopIndexInfo index; + TIntermLoop *loop; + + TLoopInfo(); + TLoopInfo(TIntermLoop *node); +}; + +class TLoopStack : public TVector +{ + public: + // Search loop stack for a loop whose index matches the input symbol. + TIntermLoop *findLoop(TIntermSymbol *symbol); + + // Find the loop index info in the loop stack by the input symbol. + TLoopIndexInfo *getIndexInfo(TIntermSymbol *symbol); + + // Update the currentValue for the next loop iteration. + void step(); + + // Return false if loop condition is no longer satisfied. + bool satisfiesLoopCondition(); + + // Check if the symbol is the index of a loop that's unrolled. + bool needsToReplaceSymbolWithValue(TIntermSymbol *symbol); + + // Return the current value of a given loop index symbol. + int getLoopIndexValue(TIntermSymbol *symbol); + + void push(TIntermLoop *info); + void pop(); +}; + +#endif // COMPILER_TRANSLATOR_LOOP_INDEX_H_ + diff --git a/src/3rdparty/angle/src/compiler/translator/MapLongVariableNames.cpp b/src/3rdparty/angle/src/compiler/translator/MapLongVariableNames.cpp deleted file mode 100644 index ef629c26b1..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/MapLongVariableNames.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// -// Copyright (c) 2002-2012 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/MapLongVariableNames.h" - -namespace { - -TString mapLongName(size_t id, const TString& name, bool isGlobal) -{ - ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE); - TStringStream stream; - stream << "webgl_"; - if (isGlobal) - stream << "g"; - stream << id; - if (name[0] != '_') - stream << "_"; - stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size()); - return stream.str(); -} - -LongNameMap* gLongNameMapInstance = NULL; - -} // anonymous namespace - -LongNameMap::LongNameMap() - : refCount(0) -{ -} - -LongNameMap::~LongNameMap() -{ -} - -// static -LongNameMap* LongNameMap::GetInstance() -{ - if (gLongNameMapInstance == NULL) - gLongNameMapInstance = new LongNameMap; - gLongNameMapInstance->refCount++; - return gLongNameMapInstance; -} - -void LongNameMap::Release() -{ - ASSERT(gLongNameMapInstance == this); - ASSERT(refCount > 0); - refCount--; - if (refCount == 0) { - delete gLongNameMapInstance; - gLongNameMapInstance = NULL; - } -} - -const char* LongNameMap::Find(const char* originalName) const -{ - std::map::const_iterator it = mLongNameMap.find( - originalName); - if (it != mLongNameMap.end()) - return (*it).second.c_str(); - return NULL; -} - -void LongNameMap::Insert(const char* originalName, const char* mappedName) -{ - mLongNameMap.insert(std::map::value_type( - originalName, mappedName)); -} - -size_t LongNameMap::Size() const -{ - return mLongNameMap.size(); -} - -MapLongVariableNames::MapLongVariableNames(LongNameMap* globalMap) -{ - ASSERT(globalMap); - mGlobalMap = globalMap; -} - -void MapLongVariableNames::visitSymbol(TIntermSymbol* symbol) -{ - ASSERT(symbol != NULL); - if (symbol->getSymbol().size() > MAX_SHORTENED_IDENTIFIER_SIZE) { - switch (symbol->getQualifier()) { - case EvqVaryingIn: - case EvqVaryingOut: - case EvqInvariantVaryingIn: - case EvqInvariantVaryingOut: - case EvqUniform: - symbol->setSymbol( - mapGlobalLongName(symbol->getSymbol())); - break; - default: - symbol->setSymbol( - mapLongName(symbol->getId(), symbol->getSymbol(), false)); - break; - }; - } -} - -TString MapLongVariableNames::mapGlobalLongName(const TString& name) -{ - ASSERT(mGlobalMap); - const char* mappedName = mGlobalMap->Find(name.c_str()); - if (mappedName != NULL) - return mappedName; - size_t id = mGlobalMap->Size(); - TString rt = mapLongName(id, name, true); - mGlobalMap->Insert(name.c_str(), rt.c_str()); - return rt; -} diff --git a/src/3rdparty/angle/src/compiler/translator/MapLongVariableNames.h b/src/3rdparty/angle/src/compiler/translator/MapLongVariableNames.h deleted file mode 100644 index 3b085a3687..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/MapLongVariableNames.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (c) 2002-2012 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. -// - -#ifndef COMPILER_MAP_LONG_VARIABLE_NAMES_H_ -#define COMPILER_MAP_LONG_VARIABLE_NAMES_H_ - -#include "GLSLANG/ShaderLang.h" - -#include "compiler/translator/intermediate.h" -#include "compiler/translator/VariableInfo.h" - -// This size does not include '\0' in the end. -#define MAX_SHORTENED_IDENTIFIER_SIZE 32 - -// This is a ref-counted singleton. GetInstance() returns a pointer to the -// singleton, and after use, call Release(). GetInstance() and Release() should -// be paired. -class LongNameMap { -public: - static LongNameMap* GetInstance(); - void Release(); - - // Return the mapped name if is in the map; - // otherwise, return NULL. - const char* Find(const char* originalName) const; - - // Insert a pair into the map. - void Insert(const char* originalName, const char* mappedName); - - // Return the number of entries in the map. - size_t Size() const; - -private: - LongNameMap(); - ~LongNameMap(); - - size_t refCount; - std::map mLongNameMap; -}; - -// Traverses intermediate tree to map attributes and uniforms names that are -// longer than MAX_SHORTENED_IDENTIFIER_SIZE to MAX_SHORTENED_IDENTIFIER_SIZE. -class MapLongVariableNames : public TIntermTraverser { -public: - MapLongVariableNames(LongNameMap* globalMap); - - virtual void visitSymbol(TIntermSymbol*); - -private: - TString mapGlobalLongName(const TString& name); - - LongNameMap* mGlobalMap; -}; - -#endif // COMPILER_MAP_LONG_VARIABLE_NAMES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp index 8367412462..65635af1ff 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -10,8 +10,9 @@ TOutputESSL::TOutputESSL(TInfoSinkBase& objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, NameMap& nameMap, - TSymbolTable& symbolTable) - : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable) + TSymbolTable& symbolTable, + int shaderVersion) + : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion) { } diff --git a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h index 2f02979a05..8a567fb8aa 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -16,7 +16,8 @@ public: ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, NameMap& nameMap, - TSymbolTable& symbolTable); + TSymbolTable& symbolTable, + int shaderVersion); protected: virtual bool writeVariablePrecision(TPrecision precision); diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp index 5589560682..eb7cbb4ae8 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -10,8 +10,9 @@ TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, NameMap& nameMap, - TSymbolTable& symbolTable) - : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable) + TSymbolTable& symbolTable, + int shaderVersion) + : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion) { } @@ -33,3 +34,24 @@ void TOutputGLSL::visitSymbol(TIntermSymbol* node) TOutputGLSLBase::visitSymbol(node); } } + +TString TOutputGLSL::translateTextureFunction(TString& name) +{ + static const char *simpleRename[] = { + "texture2DLodEXT", "texture2DLod", + "texture2DProjLodEXT", "texture2DProjLod", + "textureCubeLodEXT", "textureCubeLod", + "texture2DGradEXT", "texture2DGradARB", + "texture2DProjGradEXT", "texture2DProjGradARB", + "textureCubeGradEXT", "textureCubeGradARB", + NULL, NULL + }; + + for (int i = 0; simpleRename[i] != NULL; i += 2) { + if (name == simpleRename[i]) { + return simpleRename[i+1]; + } + } + + return name; +} diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h index e1f114d347..bceebe397d 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -16,11 +16,13 @@ public: ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, NameMap& nameMap, - TSymbolTable& symbolTable); + TSymbolTable& symbolTable, + int shaderVersion); protected: virtual bool writeVariablePrecision(TPrecision); virtual void visitSymbol(TIntermSymbol* node); + virtual TString translateTextureFunction(TString& name); }; #endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp index f2f0a3d6be..7839c04852 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -11,7 +11,7 @@ namespace { -TString arrayBrackets(const TType& type) +TString arrayBrackets(const TType &type) { ASSERT(type.isArray()); TInfoSinkBase out; @@ -19,13 +19,14 @@ TString arrayBrackets(const TType& type) return TString(out.c_str()); } -bool isSingleStatement(TIntermNode* node) { - if (const TIntermAggregate* aggregate = node->getAsAggregate()) +bool isSingleStatement(TIntermNode *node) +{ + if (const TIntermAggregate *aggregate = node->getAsAggregate()) { return (aggregate->getOp() != EOpFunction) && (aggregate->getOp() != EOpSequence); } - else if (const TIntermSelection* selection = node->getAsSelectionNode()) + else if (const TIntermSelection *selection = node->getAsSelectionNode()) { // Ternary operators are usually part of an assignment operator. // This handles those rare cases in which they are all by themselves. @@ -39,49 +40,61 @@ bool isSingleStatement(TIntermNode* node) { } } // namespace -TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink, +TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, - NameMap& nameMap, - TSymbolTable& symbolTable) + NameMap &nameMap, + TSymbolTable &symbolTable, + int shaderVersion) : TIntermTraverser(true, true, true), mObjSink(objSink), mDeclaringVariables(false), mClampingStrategy(clampingStrategy), mHashFunction(hashFunction), mNameMap(nameMap), - mSymbolTable(symbolTable) + mSymbolTable(symbolTable), + mShaderVersion(shaderVersion) { } -void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr) +void TOutputGLSLBase::writeTriplet( + Visit visit, const char *preStr, const char *inStr, const char *postStr) { - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); if (visit == PreVisit && preStr) - { out << preStr; - } else if (visit == InVisit && inStr) - { out << inStr; - } else if (visit == PostVisit && postStr) - { out << postStr; - } } -void TOutputGLSLBase::writeVariableType(const TType& type) +void TOutputGLSLBase::writeBuiltInFunctionTriplet( + Visit visit, const char *preStr, bool useEmulatedFunction) +{ + TString preString = useEmulatedFunction ? + BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr; + writeTriplet(visit, preString.c_str(), ", ", ")"); +} + +void TOutputGLSLBase::writeVariableType(const TType &type) { - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); TQualifier qualifier = type.getQualifier(); // TODO(alokp): Validate qualifier for variable declarations. - if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal)) + if (qualifier != EvqTemporary && qualifier != EvqGlobal) out << type.getQualifierString() << " "; // Declare the struct if we have not done so already. - if ((type.getBasicType() == EbtStruct) && !structDeclared(type.getStruct())) + if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) { - declareStruct(type.getStruct()); + TStructure *structure = type.getStruct(); + + declareStruct(structure); + + if (!structure->name().empty()) + { + mDeclaredStructs.insert(structure->uniqueId()); + } } else { @@ -91,19 +104,19 @@ void TOutputGLSLBase::writeVariableType(const TType& type) } } -void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args) +void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args) { - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter) { - const TIntermSymbol* arg = (*iter)->getAsSymbolNode(); + const TIntermSymbol *arg = (*iter)->getAsSymbolNode(); ASSERT(arg != NULL); - const TType& type = arg->getType(); + const TType &type = arg->getType(); writeVariableType(type); - const TString& name = arg->getSymbol(); + const TString &name = arg->getSymbol(); if (!name.empty()) out << " " << hashName(name); if (type.isArray()) @@ -115,23 +128,24 @@ void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args) } } -const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type, - const ConstantUnion* pConstUnion) +const ConstantUnion *TOutputGLSLBase::writeConstantUnion( + const TType &type, const ConstantUnion *pConstUnion) { - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); if (type.getBasicType() == EbtStruct) { - const TStructure* structure = type.getStruct(); + const TStructure *structure = type.getStruct(); out << hashName(structure->name()) << "("; - const TFieldList& fields = structure->fields(); + const TFieldList &fields = structure->fields(); for (size_t i = 0; i < fields.size(); ++i) { - const TType* fieldType = fields[i]->type(); + const TType *fieldType = fields[i]->type(); ASSERT(fieldType != NULL); pConstUnion = writeConstantUnion(*fieldType, pConstUnion); - if (i != fields.size() - 1) out << ", "; + if (i != fields.size() - 1) + out << ", "; } out << ")"; } @@ -139,28 +153,37 @@ const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type, { size_t size = type.getObjectSize(); bool writeType = size > 1; - if (writeType) out << getTypeName(type) << "("; + if (writeType) + out << getTypeName(type) << "("; for (size_t i = 0; i < size; ++i, ++pConstUnion) { switch (pConstUnion->getType()) { - case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); break; - case EbtInt: out << pConstUnion->getIConst(); break; - case EbtBool: out << pConstUnion->getBConst(); break; - default: UNREACHABLE(); + case EbtFloat: + out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); + break; + case EbtInt: + out << pConstUnion->getIConst(); + break; + case EbtBool: + out << pConstUnion->getBConst(); + break; + default: UNREACHABLE(); } - if (i != size - 1) out << ", "; + if (i != size - 1) + out << ", "; } - if (writeType) out << ")"; + if (writeType) + out << ")"; } return pConstUnion; } -void TOutputGLSLBase::visitSymbol(TIntermSymbol* node) +void TOutputGLSLBase::visitSymbol(TIntermSymbol *node) { - TInfoSinkBase& out = objSink(); - if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node)) - out << mLoopUnroll.GetLoopIndexValue(node); + TInfoSinkBase &out = objSink(); + if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node)) + out << mLoopUnrollStack.getLoopIndexValue(node); else out << hashVariableName(node->getSymbol()); @@ -168,240 +191,303 @@ void TOutputGLSLBase::visitSymbol(TIntermSymbol* node) out << arrayBrackets(node->getType()); } -void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node) +void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node) { writeConstantUnion(node->getType(), node->getUnionArrayPointer()); } -bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node) +bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) { bool visitChildren = true; - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); switch (node->getOp()) { - case EOpInitialize: + case EOpInitialize: + if (visit == InVisit) + { + out << " = "; + // RHS of initialize is not being declared. + mDeclaringVariables = false; + } + break; + case EOpAssign: + writeTriplet(visit, "(", " = ", ")"); + break; + case EOpAddAssign: + writeTriplet(visit, "(", " += ", ")"); + break; + case EOpSubAssign: + writeTriplet(visit, "(", " -= ", ")"); + break; + case EOpDivAssign: + writeTriplet(visit, "(", " /= ", ")"); + break; + // Notice the fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + writeTriplet(visit, "(", " *= ", ")"); + break; + + case EOpIndexDirect: + writeTriplet(visit, NULL, "[", "]"); + break; + case EOpIndexIndirect: + if (node->getAddIndexClamp()) + { if (visit == InVisit) { - out << " = "; - // RHS of initialize is not being declared. - mDeclaringVariables = false; + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << "[int(clamp(float("; + else + out << "[webgl_int_clamp("; } - break; - case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break; - case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break; - case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break; - case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; - // Notice the fall-through. - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: - writeTriplet(visit, "(", " *= ", ")"); - break; - - case EOpIndexDirect: - writeTriplet(visit, NULL, "[", "]"); - break; - case EOpIndexIndirect: - if (node->getAddIndexClamp()) + else if (visit == PostVisit) { - if (visit == InVisit) + int maxSize; + TIntermTyped *left = node->getLeft(); + TType leftType = left->getType(); + + if (left->isArray()) { - if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) { - out << "[int(clamp(float("; - } else { - out << "[webgl_int_clamp("; - } + // The shader will fail validation if the array length is not > 0. + maxSize = leftType.getArraySize() - 1; } - else if (visit == PostVisit) + else { - int maxSize; - TIntermTyped *left = node->getLeft(); - TType leftType = left->getType(); - - if (left->isArray()) - { - // The shader will fail validation if the array length is not > 0. - maxSize = leftType.getArraySize() - 1; - } - else - { - maxSize = leftType.getNominalSize() - 1; - } - - if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) { - out << "), 0.0, float(" << maxSize << ")))]"; - } else { - out << ", 0, " << maxSize << ")]"; - } + maxSize = leftType.getNominalSize() - 1; } + + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << "), 0.0, float(" << maxSize << ")))]"; + else + out << ", 0, " << maxSize << ")]"; } - else - { - writeTriplet(visit, NULL, "[", "]"); - } - break; - case EOpIndexDirectStruct: - if (visit == InVisit) - { - // Here we are writing out "foo.bar", where "foo" is struct - // and "bar" is field. In AST, it is represented as a binary - // node, where left child represents "foo" and right child "bar". - // The node itself represents ".". The struct field "bar" is - // actually stored as an index into TStructure::fields. - out << "."; - const TStructure* structure = node->getLeft()->getType().getStruct(); - const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion(); - const TField* field = structure->fields()[index->getIConst(0)]; - - TString fieldName = field->name(); - if (!mSymbolTable.findBuiltIn(structure->name())) - fieldName = hashName(fieldName); - - out << fieldName; - visitChildren = false; - } - break; - case EOpVectorSwizzle: - if (visit == InVisit) + } + else + { + writeTriplet(visit, NULL, "[", "]"); + } + break; + case EOpIndexDirectStruct: + if (visit == InVisit) + { + // Here we are writing out "foo.bar", where "foo" is struct + // and "bar" is field. In AST, it is represented as a binary + // node, where left child represents "foo" and right child "bar". + // The node itself represents ".". The struct field "bar" is + // actually stored as an index into TStructure::fields. + out << "."; + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; + + TString fieldName = field->name(); + if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion)) + fieldName = hashName(fieldName); + + out << fieldName; + visitChildren = false; + } + break; + case EOpVectorSwizzle: + if (visit == InVisit) + { + out << "."; + TIntermAggregate *rightChild = node->getRight()->getAsAggregate(); + TIntermSequence *sequence = rightChild->getSequence(); + for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit) { - out << "."; - TIntermAggregate* rightChild = node->getRight()->getAsAggregate(); - TIntermSequence& sequence = rightChild->getSequence(); - for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit) + TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); + ASSERT(element->getBasicType() == EbtInt); + ASSERT(element->getNominalSize() == 1); + const ConstantUnion& data = element->getUnionArrayPointer()[0]; + ASSERT(data.getType() == EbtInt); + switch (data.getIConst()) { - TIntermConstantUnion* element = (*sit)->getAsConstantUnion(); - ASSERT(element->getBasicType() == EbtInt); - ASSERT(element->getNominalSize() == 1); - const ConstantUnion& data = element->getUnionArrayPointer()[0]; - ASSERT(data.getType() == EbtInt); - switch (data.getIConst()) - { - case 0: out << "x"; break; - case 1: out << "y"; break; - case 2: out << "z"; break; - case 3: out << "w"; break; - default: UNREACHABLE(); break; - } + case 0: + out << "x"; + break; + case 1: + out << "y"; + break; + case 2: + out << "z"; + break; + case 3: + out << "w"; + break; + default: + UNREACHABLE(); } - visitChildren = false; } - break; - - case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break; - case EOpSub: writeTriplet(visit, "(", " - ", ")"); break; - case EOpMul: writeTriplet(visit, "(", " * ", ")"); break; - case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; - case EOpMod: UNIMPLEMENTED(); break; - case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; - case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break; - case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break; - case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break; - case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break; - case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break; - - // Notice the fall-through. - case EOpVectorTimesScalar: - case EOpVectorTimesMatrix: - case EOpMatrixTimesVector: - case EOpMatrixTimesScalar: - case EOpMatrixTimesMatrix: - writeTriplet(visit, "(", " * ", ")"); - break; - - case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break; - case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break; - case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break; - default: UNREACHABLE(); break; + visitChildren = false; + } + break; + + case EOpAdd: + writeTriplet(visit, "(", " + ", ")"); + break; + case EOpSub: + writeTriplet(visit, "(", " - ", ")"); + break; + case EOpMul: + writeTriplet(visit, "(", " * ", ")"); + break; + case EOpDiv: + writeTriplet(visit, "(", " / ", ")"); + break; + case EOpMod: + UNIMPLEMENTED(); + break; + case EOpEqual: + writeTriplet(visit, "(", " == ", ")"); + break; + case EOpNotEqual: + writeTriplet(visit, "(", " != ", ")"); + break; + case EOpLessThan: + writeTriplet(visit, "(", " < ", ")"); + break; + case EOpGreaterThan: + writeTriplet(visit, "(", " > ", ")"); + break; + case EOpLessThanEqual: + writeTriplet(visit, "(", " <= ", ")"); + break; + case EOpGreaterThanEqual: + writeTriplet(visit, "(", " >= ", ")"); + break; + + // Notice the fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + writeTriplet(visit, "(", " * ", ")"); + break; + + case EOpLogicalOr: + writeTriplet(visit, "(", " || ", ")"); + break; + case EOpLogicalXor: + writeTriplet(visit, "(", " ^^ ", ")"); + break; + case EOpLogicalAnd: + writeTriplet(visit, "(", " && ", ")"); + break; + default: + UNREACHABLE(); } return visitChildren; } -bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node) +bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) { TString preString; TString postString = ")"; switch (node->getOp()) { - case EOpNegative: preString = "(-"; break; - case EOpVectorLogicalNot: preString = "not("; break; - case EOpLogicalNot: preString = "(!"; break; - - case EOpPostIncrement: preString = "("; postString = "++)"; break; - case EOpPostDecrement: preString = "("; postString = "--)"; break; - case EOpPreIncrement: preString = "(++"; break; - case EOpPreDecrement: preString = "(--"; break; - - case EOpConvIntToBool: - case EOpConvFloatToBool: - switch (node->getOperand()->getType().getNominalSize()) - { - case 1: preString = "bool("; break; - case 2: preString = "bvec2("; break; - case 3: preString = "bvec3("; break; - case 4: preString = "bvec4("; break; - default: UNREACHABLE(); - } - break; - case EOpConvBoolToFloat: - case EOpConvIntToFloat: - switch (node->getOperand()->getType().getNominalSize()) - { - case 1: preString = "float("; break; - case 2: preString = "vec2("; break; - case 3: preString = "vec3("; break; - case 4: preString = "vec4("; break; - default: UNREACHABLE(); - } - break; - case EOpConvFloatToInt: - case EOpConvBoolToInt: - switch (node->getOperand()->getType().getNominalSize()) - { - case 1: preString = "int("; break; - case 2: preString = "ivec2("; break; - case 3: preString = "ivec3("; break; - case 4: preString = "ivec4("; break; - default: UNREACHABLE(); - } - break; - - case EOpRadians: preString = "radians("; break; - case EOpDegrees: preString = "degrees("; break; - case EOpSin: preString = "sin("; break; - case EOpCos: preString = "cos("; break; - case EOpTan: preString = "tan("; break; - case EOpAsin: preString = "asin("; break; - case EOpAcos: preString = "acos("; break; - case EOpAtan: preString = "atan("; break; - - case EOpExp: preString = "exp("; break; - case EOpLog: preString = "log("; break; - case EOpExp2: preString = "exp2("; break; - case EOpLog2: preString = "log2("; break; - case EOpSqrt: preString = "sqrt("; break; - case EOpInverseSqrt: preString = "inversesqrt("; break; - - case EOpAbs: preString = "abs("; break; - case EOpSign: preString = "sign("; break; - case EOpFloor: preString = "floor("; break; - case EOpCeil: preString = "ceil("; break; - case EOpFract: preString = "fract("; break; - - case EOpLength: preString = "length("; break; - case EOpNormalize: preString = "normalize("; break; - - case EOpDFdx: preString = "dFdx("; break; - case EOpDFdy: preString = "dFdy("; break; - case EOpFwidth: preString = "fwidth("; break; - - case EOpAny: preString = "any("; break; - case EOpAll: preString = "all("; break; - - default: UNREACHABLE(); break; + case EOpNegative: preString = "(-"; break; + case EOpVectorLogicalNot: preString = "not("; break; + case EOpLogicalNot: preString = "(!"; break; + + case EOpPostIncrement: preString = "("; postString = "++)"; break; + case EOpPostDecrement: preString = "("; postString = "--)"; break; + case EOpPreIncrement: preString = "(++"; break; + case EOpPreDecrement: preString = "(--"; break; + + case EOpRadians: + preString = "radians("; + break; + case EOpDegrees: + preString = "degrees("; + break; + case EOpSin: + preString = "sin("; + break; + case EOpCos: + preString = "cos("; + break; + case EOpTan: + preString = "tan("; + break; + case EOpAsin: + preString = "asin("; + break; + case EOpAcos: + preString = "acos("; + break; + case EOpAtan: + preString = "atan("; + break; + + case EOpExp: + preString = "exp("; + break; + case EOpLog: + preString = "log("; + break; + case EOpExp2: + preString = "exp2("; + break; + case EOpLog2: + preString = "log2("; + break; + case EOpSqrt: + preString = "sqrt("; + break; + case EOpInverseSqrt: + preString = "inversesqrt("; + break; + + case EOpAbs: + preString = "abs("; + break; + case EOpSign: + preString = "sign("; + break; + case EOpFloor: + preString = "floor("; + break; + case EOpCeil: + preString = "ceil("; + break; + case EOpFract: + preString = "fract("; + break; + + case EOpLength: + preString = "length("; + break; + case EOpNormalize: + preString = "normalize("; + break; + + case EOpDFdx: + preString = "dFdx("; + break; + case EOpDFdy: + preString = "dFdy("; + break; + case EOpFwidth: + preString = "fwidth("; + break; + + case EOpAny: + preString = "any("; + break; + case EOpAll: + preString = "all("; + break; + + default: + UNREACHABLE(); } if (visit == PreVisit && node->getUseEmulatedFunction()) @@ -411,9 +497,9 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node) return true; } -bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node) +bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node) { - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); if (node->usesTernaryOperator()) { @@ -448,202 +534,270 @@ bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node) return false; } -bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node) +bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) { bool visitChildren = true; - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); TString preString; - bool delayedWrite = false; + bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction()); switch (node->getOp()) { - case EOpSequence: { - // Scope the sequences except when at the global scope. - if (depth > 0) out << "{\n"; - - incrementDepth(node); - const TIntermSequence& sequence = node->getSequence(); - for (TIntermSequence::const_iterator iter = sequence.begin(); - iter != sequence.end(); ++iter) - { - TIntermNode* node = *iter; - ASSERT(node != NULL); - node->traverse(this); + case EOpSequence: + // Scope the sequences except when at the global scope. + if (mDepth > 0) + { + out << "{\n"; + } - if (isSingleStatement(node)) - out << ";\n"; - } - decrementDepth(); + incrementDepth(node); + for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); + iter != node->getSequence()->end(); ++iter) + { + TIntermNode *node = *iter; + ASSERT(node != NULL); + node->traverse(this); - // Scope the sequences except when at the global scope. - if (depth > 0) out << "}\n"; - visitChildren = false; - break; + if (isSingleStatement(node)) + out << ";\n"; } - case EOpPrototype: { - // Function declaration. - ASSERT(visit == PreVisit); - writeVariableType(node->getType()); - out << " " << hashName(node->getName()); - - out << "("; - writeFunctionParameters(node->getSequence()); - out << ")"; + decrementDepth(); - visitChildren = false; - break; - } - case EOpFunction: { - // Function definition. - ASSERT(visit == PreVisit); - writeVariableType(node->getType()); - out << " " << hashFunctionName(node->getName()); - - incrementDepth(node); - // Function definition node contains one or two children nodes - // representing function parameters and function body. The latter - // is not present in case of empty function bodies. - const TIntermSequence& sequence = node->getSequence(); - ASSERT((sequence.size() == 1) || (sequence.size() == 2)); - TIntermSequence::const_iterator seqIter = sequence.begin(); - - // Traverse function parameters. - TIntermAggregate* params = (*seqIter)->getAsAggregate(); - ASSERT(params != NULL); - ASSERT(params->getOp() == EOpParameters); - params->traverse(this); - - // Traverse function body. - TIntermAggregate* body = ++seqIter != sequence.end() ? - (*seqIter)->getAsAggregate() : NULL; - visitCodeBlock(body); - decrementDepth(); - - // Fully processed; no need to visit children. - visitChildren = false; - break; + // Scope the sequences except when at the global scope. + if (mDepth > 0) + { + out << "}\n"; } - case EOpFunctionCall: - // Function call. - if (visit == PreVisit) - { - out << hashFunctionName(node->getName()) << "("; - } - else if (visit == InVisit) - { - out << ", "; - } - else - { - out << ")"; - } - break; - case EOpParameters: { - // Function parameters. - ASSERT(visit == PreVisit); - out << "("; - writeFunctionParameters(node->getSequence()); + visitChildren = false; + break; + case EOpPrototype: + // Function declaration. + ASSERT(visit == PreVisit); + writeVariableType(node->getType()); + out << " " << hashName(node->getName()); + + out << "("; + writeFunctionParameters(*(node->getSequence())); + out << ")"; + + visitChildren = false; + break; + case EOpFunction: { + // Function definition. + ASSERT(visit == PreVisit); + writeVariableType(node->getType()); + out << " " << hashFunctionName(node->getName()); + + incrementDepth(node); + // Function definition node contains one or two children nodes + // representing function parameters and function body. The latter + // is not present in case of empty function bodies. + const TIntermSequence &sequence = *(node->getSequence()); + ASSERT((sequence.size() == 1) || (sequence.size() == 2)); + TIntermSequence::const_iterator seqIter = sequence.begin(); + + // Traverse function parameters. + TIntermAggregate *params = (*seqIter)->getAsAggregate(); + ASSERT(params != NULL); + ASSERT(params->getOp() == EOpParameters); + params->traverse(this); + + // Traverse function body. + TIntermAggregate *body = ++seqIter != sequence.end() ? + (*seqIter)->getAsAggregate() : NULL; + visitCodeBlock(body); + decrementDepth(); + + // Fully processed; no need to visit children. + visitChildren = false; + break; + } + case EOpFunctionCall: + // Function call. + if (visit == PreVisit) + out << hashFunctionName(node->getName()) << "("; + else if (visit == InVisit) + out << ", "; + else out << ")"; - visitChildren = false; - break; + break; + case EOpParameters: + // Function parameters. + ASSERT(visit == PreVisit); + out << "("; + writeFunctionParameters(*(node->getSequence())); + out << ")"; + visitChildren = false; + break; + case EOpDeclaration: + // Variable declaration. + if (visit == PreVisit) + { + const TIntermSequence &sequence = *(node->getSequence()); + const TIntermTyped *variable = sequence.front()->getAsTyped(); + writeVariableType(variable->getType()); + out << " "; + mDeclaringVariables = true; } - case EOpDeclaration: { - // Variable declaration. - if (visit == PreVisit) - { - const TIntermSequence& sequence = node->getSequence(); - const TIntermTyped* variable = sequence.front()->getAsTyped(); - writeVariableType(variable->getType()); - out << " "; - mDeclaringVariables = true; - } - else if (visit == InVisit) - { - out << ", "; - mDeclaringVariables = true; - } - else - { - mDeclaringVariables = false; - } - break; + else if (visit == InVisit) + { + out << ", "; + mDeclaringVariables = true; } - case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break; - case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break; - case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break; - case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break; - case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break; - case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break; - case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break; - case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break; - case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break; - case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break; - case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break; - case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break; - case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break; - case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break; - case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break; - case EOpConstructStruct: - if (visit == PreVisit) - { - const TType& type = node->getType(); - ASSERT(type.getBasicType() == EbtStruct); - out << hashName(type.getStruct()->name()) << "("; - } - else if (visit == InVisit) - { - out << ", "; - } - else - { - out << ")"; - } - break; - - case EOpLessThan: preString = "lessThan("; delayedWrite = true; break; - case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break; - case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break; - case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break; - case EOpVectorEqual: preString = "equal("; delayedWrite = true; break; - case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break; - case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break; - - case EOpMod: preString = "mod("; delayedWrite = true; break; - case EOpPow: preString = "pow("; delayedWrite = true; break; - case EOpAtan: preString = "atan("; delayedWrite = true; break; - case EOpMin: preString = "min("; delayedWrite = true; break; - case EOpMax: preString = "max("; delayedWrite = true; break; - case EOpClamp: preString = "clamp("; delayedWrite = true; break; - case EOpMix: preString = "mix("; delayedWrite = true; break; - case EOpStep: preString = "step("; delayedWrite = true; break; - case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break; - - case EOpDistance: preString = "distance("; delayedWrite = true; break; - case EOpDot: preString = "dot("; delayedWrite = true; break; - case EOpCross: preString = "cross("; delayedWrite = true; break; - case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break; - case EOpReflect: preString = "reflect("; delayedWrite = true; break; - case EOpRefract: preString = "refract("; delayedWrite = true; break; - case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break; - - default: UNREACHABLE(); break; + else + { + mDeclaringVariables = false; + } + break; + case EOpConstructFloat: + writeTriplet(visit, "float(", NULL, ")"); + break; + case EOpConstructVec2: + writeBuiltInFunctionTriplet(visit, "vec2(", false); + break; + case EOpConstructVec3: + writeBuiltInFunctionTriplet(visit, "vec3(", false); + break; + case EOpConstructVec4: + writeBuiltInFunctionTriplet(visit, "vec4(", false); + break; + case EOpConstructBool: + writeTriplet(visit, "bool(", NULL, ")"); + break; + case EOpConstructBVec2: + writeBuiltInFunctionTriplet(visit, "bvec2(", false); + break; + case EOpConstructBVec3: + writeBuiltInFunctionTriplet(visit, "bvec3(", false); + break; + case EOpConstructBVec4: + writeBuiltInFunctionTriplet(visit, "bvec4(", false); + break; + case EOpConstructInt: + writeTriplet(visit, "int(", NULL, ")"); + break; + case EOpConstructIVec2: + writeBuiltInFunctionTriplet(visit, "ivec2(", false); + break; + case EOpConstructIVec3: + writeBuiltInFunctionTriplet(visit, "ivec3(", false); + break; + case EOpConstructIVec4: + writeBuiltInFunctionTriplet(visit, "ivec4(", false); + break; + case EOpConstructMat2: + writeBuiltInFunctionTriplet(visit, "mat2(", false); + break; + case EOpConstructMat3: + writeBuiltInFunctionTriplet(visit, "mat3(", false); + break; + case EOpConstructMat4: + writeBuiltInFunctionTriplet(visit, "mat4(", false); + break; + case EOpConstructStruct: + if (visit == PreVisit) + { + const TType &type = node->getType(); + ASSERT(type.getBasicType() == EbtStruct); + out << hashName(type.getStruct()->name()) << "("; + } + else if (visit == InVisit) + { + out << ", "; + } + else + { + out << ")"; + } + break; + + case EOpLessThan: + writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction); + break; + case EOpGreaterThan: + writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction); + break; + case EOpLessThanEqual: + writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction); + break; + case EOpGreaterThanEqual: + writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction); + break; + case EOpVectorEqual: + writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction); + break; + case EOpVectorNotEqual: + writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction); + break; + case EOpComma: + writeTriplet(visit, NULL, ", ", NULL); + break; + + case EOpMod: + writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction); + break; + case EOpPow: + writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction); + break; + case EOpAtan: + writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction); + break; + case EOpMin: + writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction); + break; + case EOpMax: + writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction); + break; + case EOpClamp: + writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction); + break; + case EOpMix: + writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction); + break; + case EOpStep: + writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction); + break; + case EOpSmoothStep: + writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction); + break; + case EOpDistance: + writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction); + break; + case EOpDot: + writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction); + break; + case EOpCross: + writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction); + break; + case EOpFaceForward: + writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction); + break; + case EOpReflect: + writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction); + break; + case EOpRefract: + writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction); + break; + case EOpMul: + writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction); + break; + + default: + UNREACHABLE(); } - if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction()) - preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString); - if (delayedWrite) - writeTriplet(visit, preString.c_str(), ", ", ")"); return visitChildren; } -bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node) +bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node) { - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); incrementDepth(node); // Loop header. TLoopType loopType = node->getType(); if (loopType == ELoopFor) // for loop { - if (!node->getUnrollFlag()) { + if (!node->getUnrollFlag()) + { out << "for ("; if (node->getInit()) node->getInit()->traverse(this); @@ -657,6 +811,18 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node) node->getExpression()->traverse(this); out << ")\n"; } + else + { + // Need to put a one-iteration loop here to handle break. + TIntermSequence *declSeq = + node->getInit()->getAsAggregate()->getSequence(); + TIntermSymbol *indexSymbol = + (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode(); + TString name = hashVariableName(indexSymbol->getSymbol()); + out << "for (int " << name << " = 0; " + << name << " < 1; " + << "++" << name << ")\n"; + } } else if (loopType == ELoopWhile) // while loop { @@ -674,15 +840,15 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node) // Loop body. if (node->getUnrollFlag()) { - TLoopIndexInfo indexInfo; - mLoopUnroll.FillLoopIndexInfo(node, indexInfo); - mLoopUnroll.Push(indexInfo); - while (mLoopUnroll.SatisfiesLoopCondition()) + out << "{\n"; + mLoopUnrollStack.push(node); + while (mLoopUnrollStack.satisfiesLoopCondition()) { visitCodeBlock(node->getBody()); - mLoopUnroll.Step(); + mLoopUnrollStack.step(); } - mLoopUnroll.Pop(); + mLoopUnrollStack.pop(); + out << "}\n"; } else { @@ -704,21 +870,31 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node) return false; } -bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node) +bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node) { switch (node->getFlowOp()) { - case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break; - case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break; - case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break; - case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break; - default: UNREACHABLE(); break; + case EOpKill: + writeTriplet(visit, "discard", NULL, NULL); + break; + case EOpBreak: + writeTriplet(visit, "break", NULL, NULL); + break; + case EOpContinue: + writeTriplet(visit, "continue", NULL, NULL); + break; + case EOpReturn: + writeTriplet(visit, "return ", NULL, NULL); + break; + default: + UNREACHABLE(); } return true; } -void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) { +void TOutputGLSLBase::visitCodeBlock(TIntermNode *node) +{ TInfoSinkBase &out = objSink(); if (node != NULL) { @@ -734,7 +910,7 @@ void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) { } } -TString TOutputGLSLBase::getTypeName(const TType& type) +TString TOutputGLSLBase::getTypeName(const TType &type) { TInfoSinkBase out; if (type.isMatrix()) @@ -746,10 +922,17 @@ TString TOutputGLSLBase::getTypeName(const TType& type) { switch (type.getBasicType()) { - case EbtFloat: out << "vec"; break; - case EbtInt: out << "ivec"; break; - case EbtBool: out << "bvec"; break; - default: UNREACHABLE(); break; + case EbtFloat: + out << "vec"; + break; + case EbtInt: + out << "ivec"; + break; + case EbtBool: + out << "bvec"; + break; + default: + UNREACHABLE(); } out << type.getNominalSize(); } @@ -763,7 +946,7 @@ TString TOutputGLSLBase::getTypeName(const TType& type) return TString(out.c_str()); } -TString TOutputGLSLBase::hashName(const TString& name) +TString TOutputGLSLBase::hashName(const TString &name) { if (mHashFunction == NULL || name.empty()) return name; @@ -775,35 +958,41 @@ TString TOutputGLSLBase::hashName(const TString& name) return hashedName; } -TString TOutputGLSLBase::hashVariableName(const TString& name) +TString TOutputGLSLBase::hashVariableName(const TString &name) { - if (mSymbolTable.findBuiltIn(name) != NULL) + if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL) return name; return hashName(name); } -TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name) +TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name) { TString name = TFunction::unmangleName(mangled_name); - if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main") - return name; + if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main") + return translateTextureFunction(name); return hashName(name); } -bool TOutputGLSLBase::structDeclared(const TStructure* structure) const +bool TOutputGLSLBase::structDeclared(const TStructure *structure) const { - return mDeclaredStructs.find(structure->name()) != mDeclaredStructs.end(); + ASSERT(structure); + if (structure->name().empty()) + { + return false; + } + + return (mDeclaredStructs.count(structure->uniqueId()) > 0); } -void TOutputGLSLBase::declareStruct(const TStructure* structure) +void TOutputGLSLBase::declareStruct(const TStructure *structure) { - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); out << "struct " << hashName(structure->name()) << "{\n"; - const TFieldList& fields = structure->fields(); + const TFieldList &fields = structure->fields(); for (size_t i = 0; i < fields.size(); ++i) { - const TField* field = fields[i]; + const TField *field = fields[i]; if (writeVariablePrecision(field->type()->getPrecision())) out << " "; out << getTypeName(*field->type()) << " " << hashName(field->name()); @@ -812,6 +1001,5 @@ void TOutputGLSLBase::declareStruct(const TStructure* structure) out << ";\n"; } out << "}"; - - mDeclaredStructs.insert(structure->name()); } + diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h index 76bec4de61..42364de6f5 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -9,71 +9,75 @@ #include -#include "compiler/translator/ForLoopUnroll.h" #include "compiler/translator/intermediate.h" +#include "compiler/translator/LoopInfo.h" #include "compiler/translator/ParseContext.h" class TOutputGLSLBase : public TIntermTraverser { -public: - TOutputGLSLBase(TInfoSinkBase& objSink, + public: + TOutputGLSLBase(TInfoSinkBase &objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, - NameMap& nameMap, - TSymbolTable& symbolTable); - -protected: - TInfoSinkBase& objSink() { return mObjSink; } - void writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr); - void writeVariableType(const TType& type); + NameMap &nameMap, + TSymbolTable& symbolTable, + int shaderVersion); + + protected: + TInfoSinkBase &objSink() { return mObjSink; } + void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr); + void writeVariableType(const TType &type); virtual bool writeVariablePrecision(TPrecision precision) = 0; - void writeFunctionParameters(const TIntermSequence& args); - const ConstantUnion* writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion); - TString getTypeName(const TType& type); - - virtual void visitSymbol(TIntermSymbol* node); - virtual void visitConstantUnion(TIntermConstantUnion* node); - virtual bool visitBinary(Visit visit, TIntermBinary* node); - virtual bool visitUnary(Visit visit, TIntermUnary* node); - virtual bool visitSelection(Visit visit, TIntermSelection* node); - virtual bool visitAggregate(Visit visit, TIntermAggregate* node); - virtual bool visitLoop(Visit visit, TIntermLoop* node); - virtual bool visitBranch(Visit visit, TIntermBranch* node); + void writeFunctionParameters(const TIntermSequence &args); + const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *pConstUnion); + TString getTypeName(const TType &type); - void visitCodeBlock(TIntermNode* node); + virtual void visitSymbol(TIntermSymbol *node); + virtual void visitConstantUnion(TIntermConstantUnion *node); + virtual bool visitBinary(Visit visit, TIntermBinary *node); + virtual bool visitUnary(Visit visit, TIntermUnary *node); + virtual bool visitSelection(Visit visit, TIntermSelection *node); + virtual bool visitAggregate(Visit visit, TIntermAggregate *node); + virtual bool visitLoop(Visit visit, TIntermLoop *node); + virtual bool visitBranch(Visit visit, TIntermBranch *node); + void visitCodeBlock(TIntermNode *node); // Return the original name if hash function pointer is NULL; // otherwise return the hashed name. - TString hashName(const TString& name); + TString hashName(const TString &name); // Same as hashName(), but without hashing built-in variables. - TString hashVariableName(const TString& name); + TString hashVariableName(const TString &name); // Same as hashName(), but without hashing built-in functions. - TString hashFunctionName(const TString& mangled_name); + TString hashFunctionName(const TString &mangled_name); + // Used to translate function names for differences between ESSL and GLSL + virtual TString translateTextureFunction(TString &name) { return name; } -private: - bool structDeclared(const TStructure* structure) const; - void declareStruct(const TStructure* structure); + private: + bool structDeclared(const TStructure *structure) const; + void declareStruct(const TStructure *structure); - TInfoSinkBase& mObjSink; + void writeBuiltInFunctionTriplet(Visit visit, const char *preStr, bool useEmulatedFunction); + + TInfoSinkBase &mObjSink; bool mDeclaringVariables; - // Structs are declared as the tree is traversed. This set contains all - // the structs already declared. It is maintained so that a struct is - // declared only once. - typedef std::set DeclaredStructs; - DeclaredStructs mDeclaredStructs; + // This set contains all the ids of the structs from every scope. + std::set mDeclaredStructs; - ForLoopUnroll mLoopUnroll; + // Stack of loops that need to be unrolled. + TLoopStack mLoopUnrollStack; ShArrayIndexClampingStrategy mClampingStrategy; // name hashing. ShHashFunction64 mHashFunction; - NameMap& mNameMap; + NameMap &mNameMap; + + TSymbolTable &mSymbolTable; - TSymbolTable& mSymbolTable; + const int mShaderVersion; }; #endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp index af996df719..1bf1181af0 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -7,13 +7,20 @@ #include "compiler/translator/OutputHLSL.h" #include "common/angleutils.h" +#include "common/utilities.h" +#include "common/blocklayout.h" #include "compiler/translator/compilerdebug.h" -#include "compiler/translator/DetectDiscontinuity.h" #include "compiler/translator/InfoSink.h" +#include "compiler/translator/DetectDiscontinuity.h" #include "compiler/translator/SearchSymbol.h" #include "compiler/translator/UnfoldShortCircuit.h" +#include "compiler/translator/FlagStd140Structs.h" #include "compiler/translator/NodeSearch.h" #include "compiler/translator/RewriteElseBlocks.h" +#include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/util.h" +#include "compiler/translator/UniformHLSL.h" +#include "compiler/translator/StructureHLSL.h" #include #include @@ -22,27 +29,76 @@ namespace sh { +TString OutputHLSL::TextureFunction::name() const +{ + TString name = "gl_texture"; + + if (IsSampler2D(sampler)) + { + name += "2D"; + } + else if (IsSampler3D(sampler)) + { + name += "3D"; + } + else if (IsSamplerCube(sampler)) + { + name += "Cube"; + } + else UNREACHABLE(); + + if (proj) + { + name += "Proj"; + } + + if (offset) + { + name += "Offset"; + } + + switch(method) + { + case IMPLICIT: break; + case BIAS: break; // Extra parameter makes the signature unique + case LOD: name += "Lod"; break; + case LOD0: name += "Lod0"; break; + case LOD0BIAS: name += "Lod0"; break; // Extra parameter makes the signature unique + case SIZE: name += "Size"; break; + case FETCH: name += "Fetch"; break; + case GRAD: name += "Grad"; break; + default: UNREACHABLE(); + } + + return name + "("; +} + +bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const +{ + if (sampler < rhs.sampler) return true; + if (sampler > rhs.sampler) return false; + + if (coords < rhs.coords) return true; + if (coords > rhs.coords) return false; + + if (!proj && rhs.proj) return true; + if (proj && !rhs.proj) return false; + + if (!offset && rhs.offset) return true; + if (offset && !rhs.offset) return false; + + if (method < rhs.method) return true; + if (method > rhs.method) return false; + + return false; +} + OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType) : TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType) { mUnfoldShortCircuit = new UnfoldShortCircuit(context, this); mInsideFunction = false; - mUsesTexture2D = false; - mUsesTexture2D_bias = false; - mUsesTexture2DProj = false; - mUsesTexture2DProj_bias = false; - mUsesTexture2DProjLod = false; - mUsesTexture2DLod = false; - mUsesTextureCube = false; - mUsesTextureCube_bias = false; - mUsesTextureCubeLod = false; - mUsesTexture2DLod0 = false; - mUsesTexture2DLod0_bias = false; - mUsesTexture2DProjLod0 = false; - mUsesTexture2DProjLod0_bias = false; - mUsesTextureCubeLod0 = false; - mUsesTextureCubeLod0_bias = false; mUsesFragColor = false; mUsesFragData = false; mUsesDepthRange = false; @@ -68,50 +124,56 @@ OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resourc mUsesAtan2_3 = false; mUsesAtan2_4 = false; mUsesDiscardRewriting = false; + mUsesNestedBreak = false; mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; - mScopeDepth = 0; - mUniqueIndex = 0; mContainsLoopDiscontinuity = false; mOutputLod0Function = false; mInsideDiscontinuousLoop = false; + mNestedLoopDepth = 0; mExcessiveLoopIndex = NULL; + mStructureHLSL = new StructureHLSL; + mUniformHLSL = new UniformHLSL(mStructureHLSL, mOutputType); + if (mOutputType == SH_HLSL9_OUTPUT) { - if (mContext.shaderType == SH_FRAGMENT_SHADER) + if (mContext.shaderType == GL_FRAGMENT_SHADER) { - mUniformRegister = 3; // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront + // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront + mUniformHLSL->reserveUniformRegisters(3); } else { - mUniformRegister = 2; // Reserve registers for dx_DepthRange and dx_ViewAdjust + // Reserve registers for dx_DepthRange and dx_ViewAdjust + mUniformHLSL->reserveUniformRegisters(2); } } - else - { - mUniformRegister = 0; - } - mSamplerRegister = 0; + // Reserve registers for the default uniform block and driver constants + mUniformHLSL->reserveInterfaceBlockRegisters(2); } OutputHLSL::~OutputHLSL() { - delete mUnfoldShortCircuit; + SafeDelete(mUnfoldShortCircuit); + SafeDelete(mStructureHLSL); + SafeDelete(mUniformHLSL); } void OutputHLSL::output() { - mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot); + mContainsLoopDiscontinuity = mContext.shaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot); + const std::vector &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot); + makeFlaggedStructMaps(flaggedStructs); // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which // use a vertex attribute as a condition, and some related computation in the else block. - if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == SH_VERTEX_SHADER) + if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == GL_VERTEX_SHADER) { RewriteElseBlocks(mContext.treeRoot); } @@ -123,72 +185,147 @@ void OutputHLSL::output() mContext.infoSink().obj << mBody.c_str(); } +void OutputHLSL::makeFlaggedStructMaps(const std::vector &flaggedStructs) +{ + for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++) + { + TIntermTyped *flaggedNode = flaggedStructs[structIndex]; + + // This will mark the necessary block elements as referenced + flaggedNode->traverse(this); + TString structName(mBody.c_str()); + mBody.erase(); + + mFlaggedStructOriginalNames[flaggedNode] = structName; + + for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.')) + { + structName.erase(pos, 1); + } + + mFlaggedStructMappedNames[flaggedNode] = "map" + structName; + } +} + TInfoSinkBase &OutputHLSL::getBodyStream() { return mBody; } -const ActiveUniforms &OutputHLSL::getUniforms() +const std::vector &OutputHLSL::getUniforms() +{ + return mUniformHLSL->getUniforms(); +} + +const std::vector &OutputHLSL::getInterfaceBlocks() const +{ + return mUniformHLSL->getInterfaceBlocks(); +} + +const std::vector &OutputHLSL::getOutputVariables() const +{ + return mActiveOutputVariables; +} + +const std::vector &OutputHLSL::getAttributes() const +{ + return mActiveAttributes; +} + +const std::vector &OutputHLSL::getVaryings() const +{ + return mActiveVaryings; +} + +const std::map &OutputHLSL::getInterfaceBlockRegisterMap() const { - return mActiveUniforms; + return mUniformHLSL->getInterfaceBlockRegisterMap(); +} + +const std::map &OutputHLSL::getUniformRegisterMap() const +{ + return mUniformHLSL->getUniformRegisterMap(); } int OutputHLSL::vectorSize(const TType &type) const { - int elementSize = type.isMatrix() ? type.getNominalSize() : 1; + int elementSize = type.isMatrix() ? type.getCols() : 1; int arraySize = type.isArray() ? type.getArraySize() : 1; return elementSize * arraySize; } -void OutputHLSL::header() +TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName) { - ShShaderType shaderType = mContext.shaderType; - TInfoSinkBase &out = mHeader; + TString init; + + TString preIndentString; + TString fullIndentString; - for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++) + for (int spaces = 0; spaces < (indent * 4); spaces++) { - out << *structDeclaration; + preIndentString += ' '; } - for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++) + for (int spaces = 0; spaces < ((indent+1) * 4); spaces++) { - out << *constructor; + fullIndentString += ' '; } - TString uniforms; - TString varyings; - TString attributes; + init += preIndentString + "{\n"; - for (ReferencedSymbols::const_iterator uniform = mReferencedUniforms.begin(); uniform != mReferencedUniforms.end(); uniform++) + const TFieldList &fields = structure.fields(); + for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) { - const TType &type = uniform->second->getType(); - const TString &name = uniform->second->getSymbol(); + const TField &field = *fields[fieldIndex]; + const TString &fieldName = rhsStructName + "." + Decorate(field.name()); + const TType &fieldType = *field.type(); - if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture + if (fieldType.getStruct()) { - int index = samplerRegister(mReferencedUniforms[name]); - - uniforms += "uniform SamplerState sampler_" + decorateUniform(name, type) + arrayString(type) + - " : register(s" + str(index) + ");\n"; - - uniforms += "uniform " + textureString(type) + " texture_" + decorateUniform(name, type) + arrayString(type) + - " : register(t" + str(index) + ");\n"; + init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName); } else { - uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + - " : register(" + registerString(mReferencedUniforms[name]) + ");\n"; + init += fullIndentString + fieldName + ",\n"; } } + init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n"; + + return init; +} + +void OutputHLSL::header() +{ + TInfoSinkBase &out = mHeader; + + TString varyings; + TString attributes; + TString flaggedStructs; + + for (std::map::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++) + { + TIntermTyped *structNode = flaggedStructIt->first; + const TString &mappedName = flaggedStructIt->second; + const TStructure &structure = *structNode->getType().getStruct(); + const TString &originalName = mFlaggedStructOriginalNames[structNode]; + + flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n"; + flaggedStructs += structInitializerString(0, structure, originalName); + flaggedStructs += "\n"; + } + for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++) { const TType &type = varying->second->getType(); const TString &name = varying->second->getSymbol(); // Program linking depends on this exact format - varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n"; + varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + " " + + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n"; + + declareVaryingToList(type, type.getQualifier(), name, mActiveVaryings); } for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++) @@ -196,36 +333,71 @@ void OutputHLSL::header() const TType &type = attribute->second->getType(); const TString &name = attribute->second->getSymbol(); - attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n"; + attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n"; + + sh::Attribute attributeVar(GLVariableType(type), GLVariablePrecision(type), name.c_str(), + (unsigned int)type.getArraySize(), type.getLayoutQualifier().location); + mActiveAttributes.push_back(attributeVar); } + out << mStructureHLSL->structsHeader(); + + out << mUniformHLSL->uniformsHeader(mOutputType, mReferencedUniforms); + out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks); + if (mUsesDiscardRewriting) { out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n"; } - if (shaderType == SH_FRAGMENT_SHADER) + if (mUsesNestedBreak) + { + out << "#define ANGLE_USES_NESTED_BREAK" << "\n"; + } + + if (mContext.shaderType == GL_FRAGMENT_SHADER) { TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers"); const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire)); - const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1; - out << "// Varyings\n"; out << varyings; - out << "\n" - "static float4 gl_Color[" << numColorValues << "] =\n" - "{\n"; - for (unsigned int i = 0; i < numColorValues; i++) + out << "\n"; + + if (mContext.getShaderVersion() >= 300) { - out << " float4(0, 0, 0, 0)"; - if (i + 1 != numColorValues) + for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++) { - out << ","; + const TString &variableName = outputVariableIt->first; + const TType &variableType = outputVariableIt->second->getType(); + const TLayoutQualifier &layoutQualifier = variableType.getLayoutQualifier(); + + out << "static " + TypeString(variableType) + " out_" + variableName + ArrayString(variableType) + + " = " + initializer(variableType) + ";\n"; + + sh::Attribute outputVar(GLVariableType(variableType), GLVariablePrecision(variableType), variableName.c_str(), + (unsigned int)variableType.getArraySize(), layoutQualifier.location); + mActiveOutputVariables.push_back(outputVar); } - out << "\n"; } - out << "};\n"; + else + { + const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1; + + out << "static float4 gl_Color[" << numColorValues << "] =\n" + "{\n"; + for (unsigned int i = 0; i < numColorValues; i++) + { + out << " float4(0, 0, 0, 0)"; + if (i + 1 != numColorValues) + { + out << ","; + } + out << "\n"; + } + + out << "};\n"; + } if (mUsesFragDepth) { @@ -307,523 +479,713 @@ void OutputHLSL::header() out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" "\n"; } - - out << uniforms; + + if (!flaggedStructs.empty()) + { + out << "// Std140 Structures accessed by value\n"; + out << "\n"; + out << flaggedStructs; + out << "\n"; + } + + if (usingMRTExtension && mNumRenderTargets > 1) + { + out << "#define GL_USES_MRT\n"; + } + + if (mUsesFragColor) + { + out << "#define GL_USES_FRAG_COLOR\n"; + } + + if (mUsesFragData) + { + out << "#define GL_USES_FRAG_DATA\n"; + } + } + else // Vertex shader + { + out << "// Attributes\n"; + out << attributes; + out << "\n" + "static float4 gl_Position = float4(0, 0, 0, 0);\n"; + + if (mUsesPointSize) + { + out << "static float gl_PointSize = float(1);\n"; + } + + out << "\n" + "// Varyings\n"; + out << varyings; out << "\n"; - if (mUsesTexture2D) + if (mUsesDepthRange) { - if (mOutputType == SH_HLSL9_OUTPUT) - { - out << "float4 gl_texture2D(sampler2D s, float2 t)\n" - "{\n" - " return tex2D(s, t);\n" - "}\n" - "\n"; - } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv)\n" - "{\n" - " return t.Sample(s, uv);\n" - "}\n" - "\n"; - } - else UNREACHABLE(); + out << "struct gl_DepthRangeParameters\n" + "{\n" + " float near;\n" + " float far;\n" + " float diff;\n" + "};\n" + "\n"; } - if (mUsesTexture2D_bias) + if (mOutputType == SH_HLSL11_OUTPUT) { - if (mOutputType == SH_HLSL9_OUTPUT) + if (mUsesDepthRange) { - out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n" + out << "cbuffer DriverConstants : register(b1)\n" "{\n" - " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n" - "}\n" + " float3 dx_DepthRange : packoffset(c0);\n" + "};\n" "\n"; } - else if (mOutputType == SH_HLSL11_OUTPUT) + } + else + { + if (mUsesDepthRange) { - out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv, float bias)\n" - "{\n" - " return t.SampleBias(s, uv, bias);\n" - "}\n" - "\n"; + out << "uniform float3 dx_DepthRange : register(c0);\n"; } - else UNREACHABLE(); + + out << "uniform float4 dx_ViewAdjust : register(c1);\n" + "\n"; } - if (mUsesTexture2DProj) + if (mUsesDepthRange) { - if (mOutputType == SH_HLSL9_OUTPUT) - { - out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n" - "{\n" - " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n" - "}\n" - "\n" - "float4 gl_texture2DProj(sampler2D s, float4 t)\n" - "{\n" - " return tex2Dproj(s, t);\n" - "}\n" - "\n"; - } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw)\n" - "{\n" - " return t.Sample(s, float2(uvw.x / uvw.z, uvw.y / uvw.z));\n" - "}\n" - "\n" - "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n" - "{\n" - " return t.Sample(s, float2(uvw.x / uvw.w, uvw.y / uvw.w));\n" - "}\n" - "\n"; - } - else UNREACHABLE(); + out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" + "\n"; } - if (mUsesTexture2DProj_bias) + if (!flaggedStructs.empty()) { - if (mOutputType == SH_HLSL9_OUTPUT) + out << "// Std140 Structures accessed by value\n"; + out << "\n"; + out << flaggedStructs; + out << "\n"; + } + } + + for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++) + { + // Return type + if (textureFunction->method == TextureFunction::SIZE) + { + switch(textureFunction->sampler) { - out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n" - "{\n" - " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n" - "}\n" - "\n" - "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n" - "{\n" - " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n" - "}\n" - "\n"; + case EbtSampler2D: out << "int2 "; break; + case EbtSampler3D: out << "int3 "; break; + case EbtSamplerCube: out << "int2 "; break; + case EbtSampler2DArray: out << "int3 "; break; + case EbtISampler2D: out << "int2 "; break; + case EbtISampler3D: out << "int3 "; break; + case EbtISamplerCube: out << "int2 "; break; + case EbtISampler2DArray: out << "int3 "; break; + case EbtUSampler2D: out << "int2 "; break; + case EbtUSampler3D: out << "int3 "; break; + case EbtUSamplerCube: out << "int2 "; break; + case EbtUSampler2DArray: out << "int3 "; break; + case EbtSampler2DShadow: out << "int2 "; break; + case EbtSamplerCubeShadow: out << "int2 "; break; + case EbtSampler2DArrayShadow: out << "int3 "; break; + default: UNREACHABLE(); } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw, float bias)\n" - "{\n" - " return t.SampleBias(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), bias);\n" - "}\n" - "\n" - "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw, float bias)\n" - "{\n" - " return t.SampleBias(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), bias);\n" - "}\n" - "\n"; + } + else // Sampling function + { + switch(textureFunction->sampler) + { + case EbtSampler2D: out << "float4 "; break; + case EbtSampler3D: out << "float4 "; break; + case EbtSamplerCube: out << "float4 "; break; + case EbtSampler2DArray: out << "float4 "; break; + case EbtISampler2D: out << "int4 "; break; + case EbtISampler3D: out << "int4 "; break; + case EbtISamplerCube: out << "int4 "; break; + case EbtISampler2DArray: out << "int4 "; break; + case EbtUSampler2D: out << "uint4 "; break; + case EbtUSampler3D: out << "uint4 "; break; + case EbtUSamplerCube: out << "uint4 "; break; + case EbtUSampler2DArray: out << "uint4 "; break; + case EbtSampler2DShadow: out << "float "; break; + case EbtSamplerCubeShadow: out << "float "; break; + case EbtSampler2DArrayShadow: out << "float "; break; + default: UNREACHABLE(); } - else UNREACHABLE(); } - if (mUsesTextureCube) + // Function name + out << textureFunction->name(); + + // Argument list + int hlslCoords = 4; + + if (mOutputType == SH_HLSL9_OUTPUT) { - if (mOutputType == SH_HLSL9_OUTPUT) + switch(textureFunction->sampler) { - out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n" - "{\n" - " return texCUBE(s, t);\n" - "}\n" - "\n"; + case EbtSampler2D: out << "sampler2D s"; hlslCoords = 2; break; + case EbtSamplerCube: out << "samplerCUBE s"; hlslCoords = 3; break; + default: UNREACHABLE(); } - else if (mOutputType == SH_HLSL11_OUTPUT) + + switch(textureFunction->method) { - out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw)\n" - "{\n" - " return t.Sample(s, uvw);\n" - "}\n" - "\n"; + case TextureFunction::IMPLICIT: break; + case TextureFunction::BIAS: hlslCoords = 4; break; + case TextureFunction::LOD: hlslCoords = 4; break; + case TextureFunction::LOD0: hlslCoords = 4; break; + case TextureFunction::LOD0BIAS: hlslCoords = 4; break; + default: UNREACHABLE(); + } + } + else if (mOutputType == SH_HLSL11_OUTPUT) + { + switch(textureFunction->sampler) + { + case EbtSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break; + case EbtSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break; + case EbtSamplerCube: out << "TextureCube x, SamplerState s"; hlslCoords = 3; break; + case EbtSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; + case EbtISampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break; + case EbtISampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break; + case EbtISamplerCube: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; + case EbtISampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; + case EbtUSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break; + case EbtUSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break; + case EbtUSamplerCube: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; + case EbtUSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; + case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break; + case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break; + case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break; + default: UNREACHABLE(); } - else UNREACHABLE(); } + else UNREACHABLE(); - if (mUsesTextureCube_bias) + if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates { - if (mOutputType == SH_HLSL9_OUTPUT) + switch(textureFunction->coords) { - out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n" - "{\n" - " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n" - "}\n" - "\n"; + case 2: out << ", int2 t"; break; + case 3: out << ", int3 t"; break; + default: UNREACHABLE(); } - else if (mOutputType == SH_HLSL11_OUTPUT) + } + else // Floating-point coordinates (except textureSize) + { + switch(textureFunction->coords) { - out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw, float bias)\n" - "{\n" - " return t.SampleBias(s, uvw, bias);\n" - "}\n" - "\n"; + case 1: out << ", int lod"; break; // textureSize() + case 2: out << ", float2 t"; break; + case 3: out << ", float3 t"; break; + case 4: out << ", float4 t"; break; + default: UNREACHABLE(); } - else UNREACHABLE(); } - // These *Lod0 intrinsics are not available in GL fragment shaders. - // They are used to sample using discontinuous texture coordinates. - if (mUsesTexture2DLod0) - { - if (mOutputType == SH_HLSL9_OUTPUT) - { - out << "float4 gl_texture2DLod0(sampler2D s, float2 t)\n" - "{\n" - " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n" - "}\n" - "\n"; + if (textureFunction->method == TextureFunction::GRAD) + { + switch(textureFunction->sampler) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + out << ", float2 ddx, float2 ddy"; + break; + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + out << ", float3 ddx, float3 ddy"; + break; + default: UNREACHABLE(); } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_texture2DLod0(Texture2D t, SamplerState s, float2 uv)\n" - "{\n" - " return t.SampleLevel(s, uv, 0);\n" - "}\n" - "\n"; - } - else UNREACHABLE(); } - if (mUsesTexture2DLod0_bias) + switch(textureFunction->method) { - if (mOutputType == SH_HLSL9_OUTPUT) - { - out << "float4 gl_texture2DLod0(sampler2D s, float2 t, float bias)\n" - "{\n" - " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n" - "}\n" - "\n"; - } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_texture2DLod0(Texture2D t, SamplerState s, float2 uv, float bias)\n" - "{\n" - " return t.SampleLevel(s, uv, 0);\n" - "}\n" - "\n"; - } - else UNREACHABLE(); + case TextureFunction::IMPLICIT: break; + case TextureFunction::BIAS: break; // Comes after the offset parameter + case TextureFunction::LOD: out << ", float lod"; break; + case TextureFunction::LOD0: break; + case TextureFunction::LOD0BIAS: break; // Comes after the offset parameter + case TextureFunction::SIZE: break; + case TextureFunction::FETCH: out << ", int mip"; break; + case TextureFunction::GRAD: break; + default: UNREACHABLE(); } - if (mUsesTexture2DProjLod0) + if (textureFunction->offset) { - if (mOutputType == SH_HLSL9_OUTPUT) + switch(textureFunction->sampler) { - out << "float4 gl_texture2DProjLod0(sampler2D s, float3 t)\n" - "{\n" - " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n" - "}\n" - "\n" - "float4 gl_texture2DProjLod(sampler2D s, float4 t)\n" - "{\n" - " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n" - "}\n" - "\n"; - } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_texture2DProjLod0(Texture2D t, SamplerState s, float3 uvw)\n" - "{\n" - " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n" - "}\n" - "\n" - "float4 gl_texture2DProjLod0(Texture2D t, SamplerState s, float4 uvw)\n" - "{\n" - " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n" - "}\n" - "\n"; + case EbtSampler2D: out << ", int2 offset"; break; + case EbtSampler3D: out << ", int3 offset"; break; + case EbtSampler2DArray: out << ", int2 offset"; break; + case EbtISampler2D: out << ", int2 offset"; break; + case EbtISampler3D: out << ", int3 offset"; break; + case EbtISampler2DArray: out << ", int2 offset"; break; + case EbtUSampler2D: out << ", int2 offset"; break; + case EbtUSampler3D: out << ", int3 offset"; break; + case EbtUSampler2DArray: out << ", int2 offset"; break; + case EbtSampler2DShadow: out << ", int2 offset"; break; + case EbtSampler2DArrayShadow: out << ", int2 offset"; break; + default: UNREACHABLE(); } - else UNREACHABLE(); } - if (mUsesTexture2DProjLod0_bias) + if (textureFunction->method == TextureFunction::BIAS || + textureFunction->method == TextureFunction::LOD0BIAS) { - if (mOutputType == SH_HLSL9_OUTPUT) - { - out << "float4 gl_texture2DProjLod0_bias(sampler2D s, float3 t, float bias)\n" - "{\n" - " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n" - "}\n" - "\n" - "float4 gl_texture2DProjLod_bias(sampler2D s, float4 t, float bias)\n" - "{\n" - " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n" - "}\n" - "\n"; - } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_texture2DProjLod_bias(Texture2D t, SamplerState s, float3 uvw, float bias)\n" - "{\n" - " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n" - "}\n" - "\n" - "float4 gl_texture2DProjLod_bias(Texture2D t, SamplerState s, float4 uvw, float bias)\n" - "{\n" - " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n" - "}\n" - "\n"; - } - else UNREACHABLE(); + out << ", float bias"; } - if (mUsesTextureCubeLod0) + out << ")\n" + "{\n"; + + if (textureFunction->method == TextureFunction::SIZE) { - if (mOutputType == SH_HLSL9_OUTPUT) + if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler)) { - out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t)\n" - "{\n" - " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n" - "}\n" - "\n"; + if (IsSamplerArray(textureFunction->sampler)) + { + out << " uint width; uint height; uint layers; uint numberOfLevels;\n" + " x.GetDimensions(lod, width, height, layers, numberOfLevels);\n"; + } + else + { + out << " uint width; uint height; uint numberOfLevels;\n" + " x.GetDimensions(lod, width, height, numberOfLevels);\n"; + } } - else if (mOutputType == SH_HLSL11_OUTPUT) + else if (IsSampler3D(textureFunction->sampler)) { - out << "float4 gl_textureCubeLod0(TextureCube t, SamplerState s, float3 uvw)\n" - "{\n" - " return t.SampleLevel(s, uvw, 0);\n" - "}\n" - "\n"; + out << " uint width; uint height; uint depth; uint numberOfLevels;\n" + " x.GetDimensions(lod, width, height, depth, numberOfLevels);\n"; } else UNREACHABLE(); - } - if (mUsesTextureCubeLod0_bias) - { - if (mOutputType == SH_HLSL9_OUTPUT) - { - out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t, float bias)\n" - "{\n" - " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n" - "}\n" - "\n"; - } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_textureCubeLod0(TextureCube t, SamplerState s, float3 uvw, float bias)\n" - "{\n" - " return t.SampleLevel(s, uvw, 0);\n" - "}\n" - "\n"; + switch(textureFunction->sampler) + { + case EbtSampler2D: out << " return int2(width, height);"; break; + case EbtSampler3D: out << " return int3(width, height, depth);"; break; + case EbtSamplerCube: out << " return int2(width, height);"; break; + case EbtSampler2DArray: out << " return int3(width, height, layers);"; break; + case EbtISampler2D: out << " return int2(width, height);"; break; + case EbtISampler3D: out << " return int3(width, height, depth);"; break; + case EbtISamplerCube: out << " return int2(width, height);"; break; + case EbtISampler2DArray: out << " return int3(width, height, layers);"; break; + case EbtUSampler2D: out << " return int2(width, height);"; break; + case EbtUSampler3D: out << " return int3(width, height, depth);"; break; + case EbtUSamplerCube: out << " return int2(width, height);"; break; + case EbtUSampler2DArray: out << " return int3(width, height, layers);"; break; + case EbtSampler2DShadow: out << " return int2(width, height);"; break; + case EbtSamplerCubeShadow: out << " return int2(width, height);"; break; + case EbtSampler2DArrayShadow: out << " return int3(width, height, layers);"; break; + default: UNREACHABLE(); } - else UNREACHABLE(); } - - if (usingMRTExtension && mNumRenderTargets > 1) + else { - out << "#define GL_USES_MRT\n"; - } + if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler)) + { + out << " float width; float height; float layers; float levels;\n"; - if (mUsesFragColor) - { - out << "#define GL_USES_FRAG_COLOR\n"; - } + out << " uint mip = 0;\n"; - if (mUsesFragData) - { - out << "#define GL_USES_FRAG_DATA\n"; - } - } - else // Vertex shader - { - out << "// Attributes\n"; - out << attributes; - out << "\n" - "static float4 gl_Position = float4(0, 0, 0, 0);\n"; - - if (mUsesPointSize) - { - out << "static float gl_PointSize = float(1);\n"; - } + out << " x.GetDimensions(mip, width, height, layers, levels);\n"; - out << "\n" - "// Varyings\n"; - out << varyings; - out << "\n"; + out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n"; + out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n"; + out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n"; + out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || (zMajor && t.z < 0.0f);\n"; - if (mUsesDepthRange) - { - out << "struct gl_DepthRangeParameters\n" - "{\n" - " float near;\n" - " float far;\n" - " float diff;\n" - "};\n" - "\n"; - } + // FACE_POSITIVE_X = 000b + // FACE_NEGATIVE_X = 001b + // FACE_POSITIVE_Y = 010b + // FACE_NEGATIVE_Y = 011b + // FACE_POSITIVE_Z = 100b + // FACE_NEGATIVE_Z = 101b + out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n"; - if (mOutputType == SH_HLSL11_OUTPUT) - { - if (mUsesDepthRange) - { - out << "cbuffer DriverConstants : register(b1)\n" - "{\n" - " float3 dx_DepthRange : packoffset(c0);\n" - "};\n" - "\n"; + out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n"; + out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n"; + out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n"; + + out << " t.x = (u * 0.5f / m) + 0.5f;\n"; + out << " t.y = (v * 0.5f / m) + 0.5f;\n"; } - } - else - { - if (mUsesDepthRange) + else if (IsIntegerSampler(textureFunction->sampler) && + textureFunction->method != TextureFunction::FETCH) { - out << "uniform float3 dx_DepthRange : register(c0);\n"; - } + if (IsSampler2D(textureFunction->sampler)) + { + if (IsSamplerArray(textureFunction->sampler)) + { + out << " float width; float height; float layers; float levels;\n"; - out << "uniform float4 dx_ViewAdjust : register(c1);\n" - "\n"; - } + if (textureFunction->method == TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction->method == TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + if (textureFunction->method == TextureFunction::IMPLICIT || + textureFunction->method == TextureFunction::BIAS) + { + out << " x.GetDimensions(0, width, height, layers, levels);\n" + " float2 tSized = float2(t.x * width, t.y * height);\n" + " float dx = length(ddx(tSized));\n" + " float dy = length(ddy(tSized));\n" + " float lod = log2(max(dx, dy));\n"; + + if (textureFunction->method == TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction->method == TextureFunction::GRAD) + { + out << " x.GetDimensions(0, width, height, layers, levels);\n" + " float lod = log2(max(length(ddx), length(ddy)));\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } - if (mUsesDepthRange) - { - out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" - "\n"; - } + out << " x.GetDimensions(mip, width, height, layers, levels);\n"; + } + else + { + out << " float width; float height; float levels;\n"; - out << uniforms; - out << "\n"; - - if (mUsesTexture2D) - { - if (mOutputType == SH_HLSL9_OUTPUT) - { - out << "float4 gl_texture2D(sampler2D s, float2 t)\n" - "{\n" - " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n" - "}\n" - "\n"; - } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv)\n" - "{\n" - " return t.SampleLevel(s, uv, 0);\n" - "}\n" - "\n"; - } - else UNREACHABLE(); - } + if (textureFunction->method == TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction->method == TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + if (textureFunction->method == TextureFunction::IMPLICIT || + textureFunction->method == TextureFunction::BIAS) + { + out << " x.GetDimensions(0, width, height, levels);\n" + " float2 tSized = float2(t.x * width, t.y * height);\n" + " float dx = length(ddx(tSized));\n" + " float dy = length(ddy(tSized));\n" + " float lod = log2(max(dx, dy));\n"; + + if (textureFunction->method == TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction->method == TextureFunction::LOD) + { + out << " x.GetDimensions(0, width, height, levels);\n"; + } + else if (textureFunction->method == TextureFunction::GRAD) + { + out << " x.GetDimensions(0, width, height, levels);\n" + " float lod = log2(max(length(ddx), length(ddy)));\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } - if (mUsesTexture2DLod) - { - if (mOutputType == SH_HLSL9_OUTPUT) - { - out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n" - "{\n" - " return tex2Dlod(s, float4(t.x, t.y, 0, lod));\n" - "}\n" - "\n"; - } - else if (mOutputType == SH_HLSL11_OUTPUT) - { - out << "float4 gl_texture2DLod(Texture2D t, SamplerState s, float2 uv, float lod)\n" - "{\n" - " return t.SampleLevel(s, uv, lod);\n" - "}\n" - "\n"; + out << " x.GetDimensions(mip, width, height, levels);\n"; + } + } + else if (IsSampler3D(textureFunction->sampler)) + { + out << " float width; float height; float depth; float levels;\n"; + + if (textureFunction->method == TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction->method == TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + if (textureFunction->method == TextureFunction::IMPLICIT || + textureFunction->method == TextureFunction::BIAS) + { + out << " x.GetDimensions(0, width, height, depth, levels);\n" + " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n" + " float dx = length(ddx(tSized));\n" + " float dy = length(ddy(tSized));\n" + " float lod = log2(max(dx, dy));\n"; + + if (textureFunction->method == TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction->method == TextureFunction::GRAD) + { + out << " x.GetDimensions(0, width, height, depth, levels);\n" + " float lod = log2(max(length(ddx), length(ddy)));\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " x.GetDimensions(mip, width, height, depth, levels);\n"; + } + else UNREACHABLE(); } - else UNREACHABLE(); - } - if (mUsesTexture2DProj) - { + out << " return "; + + // HLSL intrinsic if (mOutputType == SH_HLSL9_OUTPUT) { - out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n" - "{\n" - " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n" - "}\n" - "\n" - "float4 gl_texture2DProj(sampler2D s, float4 t)\n" - "{\n" - " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n" - "}\n" - "\n"; + switch(textureFunction->sampler) + { + case EbtSampler2D: out << "tex2D"; break; + case EbtSamplerCube: out << "texCUBE"; break; + default: UNREACHABLE(); + } + + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: out << "(s, "; break; + case TextureFunction::BIAS: out << "bias(s, "; break; + case TextureFunction::LOD: out << "lod(s, "; break; + case TextureFunction::LOD0: out << "lod(s, "; break; + case TextureFunction::LOD0BIAS: out << "lod(s, "; break; + default: UNREACHABLE(); + } } else if (mOutputType == SH_HLSL11_OUTPUT) { - out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw)\n" - "{\n" - " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n" - "}\n" - "\n" - "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n" - "{\n" - " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n" - "}\n" - "\n"; + if (textureFunction->method == TextureFunction::GRAD) + { + if (IsIntegerSampler(textureFunction->sampler)) + { + out << "x.Load("; + } + else if (IsShadowSampler(textureFunction->sampler)) + { + out << "x.SampleCmpLevelZero(s, "; + } + else + { + out << "x.SampleGrad(s, "; + } + } + else if (IsIntegerSampler(textureFunction->sampler) || + textureFunction->method == TextureFunction::FETCH) + { + out << "x.Load("; + } + else if (IsShadowSampler(textureFunction->sampler)) + { + out << "x.SampleCmp(s, "; + } + else + { + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: out << "x.Sample(s, "; break; + case TextureFunction::BIAS: out << "x.SampleBias(s, "; break; + case TextureFunction::LOD: out << "x.SampleLevel(s, "; break; + case TextureFunction::LOD0: out << "x.SampleLevel(s, "; break; + case TextureFunction::LOD0BIAS: out << "x.SampleLevel(s, "; break; + default: UNREACHABLE(); + } + } } else UNREACHABLE(); - } - if (mUsesTexture2DProjLod) - { - if (mOutputType == SH_HLSL9_OUTPUT) + // Integer sampling requires integer addresses + TString addressx = ""; + TString addressy = ""; + TString addressz = ""; + TString close = ""; + + if (IsIntegerSampler(textureFunction->sampler) || + textureFunction->method == TextureFunction::FETCH) { - out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n" - "{\n" - " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, lod));\n" - "}\n" - "\n" - "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n" - "{\n" - " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, lod));\n" - "}\n" - "\n"; + switch(hlslCoords) + { + case 2: out << "int3("; break; + case 3: out << "int4("; break; + default: UNREACHABLE(); + } + + // Convert from normalized floating-point to integer + if (textureFunction->method != TextureFunction::FETCH) + { + addressx = "int(floor(width * frac(("; + addressy = "int(floor(height * frac(("; + + if (IsSamplerArray(textureFunction->sampler)) + { + addressz = "int(max(0, min(layers - 1, floor(0.5 + "; + } + else if (IsSamplerCube(textureFunction->sampler)) + { + addressz = "(((("; + } + else + { + addressz = "int(floor(depth * frac(("; + } + + close = "))))"; + } } - else if (mOutputType == SH_HLSL11_OUTPUT) + else { - out << "float4 gl_texture2DProjLod(Texture2D t, SamplerState s, float3 uvw, float lod)\n" - "{\n" - " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), lod);\n" - "}\n" - "\n" - "float4 gl_texture2DProjLod(Texture2D t, SamplerState s, float4 uvw, float lod)\n" - "{\n" - " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), lod);\n" - "}\n" - "\n"; + switch(hlslCoords) + { + case 2: out << "float2("; break; + case 3: out << "float3("; break; + case 4: out << "float4("; break; + default: UNREACHABLE(); + } } - else UNREACHABLE(); - } - if (mUsesTextureCube) - { - if (mOutputType == SH_HLSL9_OUTPUT) - { - out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n" - "{\n" - " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n" - "}\n" - "\n"; - } - else if (mOutputType == SH_HLSL11_OUTPUT) + TString proj = ""; // Only used for projected textures + + if (textureFunction->proj) { - out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw)\n" - "{\n" - " return t.SampleLevel(s, uvw, 0);\n" - "}\n" - "\n"; + switch(textureFunction->coords) + { + case 3: proj = " / t.z"; break; + case 4: proj = " / t.w"; break; + default: UNREACHABLE(); + } } - else UNREACHABLE(); - } - if (mUsesTextureCubeLod) - { + out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close; + if (mOutputType == SH_HLSL9_OUTPUT) { - out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n" - "{\n" - " return texCUBElod(s, float4(t.x, t.y, t.z, lod));\n" - "}\n" - "\n"; + if (hlslCoords >= 3) + { + if (textureFunction->coords < 3) + { + out << ", 0"; + } + else + { + out << ", t.z" + proj; + } + } + + if (hlslCoords == 4) + { + switch(textureFunction->method) + { + case TextureFunction::BIAS: out << ", bias"; break; + case TextureFunction::LOD: out << ", lod"; break; + case TextureFunction::LOD0: out << ", 0"; break; + case TextureFunction::LOD0BIAS: out << ", bias"; break; + default: UNREACHABLE(); + } + } + + out << "));\n"; } else if (mOutputType == SH_HLSL11_OUTPUT) { - out << "float4 gl_textureCubeLod(TextureCube t, SamplerState s, float3 uvw, float lod)\n" - "{\n" - " return t.SampleLevel(s, uvw, lod);\n" - "}\n" - "\n"; + if (hlslCoords >= 3) + { + if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler)) + { + out << ", face"; + } + else + { + out << ", " + addressz + ("t.z" + proj) + close; + } + } + + if (textureFunction->method == TextureFunction::GRAD) + { + if (IsIntegerSampler(textureFunction->sampler)) + { + out << ", mip)"; + } + else if (IsShadowSampler(textureFunction->sampler)) + { + // Compare value + switch(textureFunction->coords) + { + case 3: out << "), t.z"; break; + case 4: out << "), t.w"; break; + default: UNREACHABLE(); + } + } + else + { + out << "), ddx, ddy"; + } + } + else if (IsIntegerSampler(textureFunction->sampler) || + textureFunction->method == TextureFunction::FETCH) + { + out << ", mip)"; + } + else if (IsShadowSampler(textureFunction->sampler)) + { + // Compare value + switch(textureFunction->coords) + { + case 3: out << "), t.z"; break; + case 4: out << "), t.w"; break; + default: UNREACHABLE(); + } + } + else + { + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: out << ")"; break; + case TextureFunction::BIAS: out << "), bias"; break; + case TextureFunction::LOD: out << "), lod"; break; + case TextureFunction::LOD0: out << "), 0"; break; + case TextureFunction::LOD0BIAS: out << "), bias"; break; + default: UNREACHABLE(); + } + } + + if (textureFunction->offset) + { + out << ", offset"; + } + + out << ");"; } else UNREACHABLE(); } + + out << "\n" + "}\n" + "\n"; } if (mUsesFragCoord) @@ -891,7 +1253,7 @@ void OutputHLSL::header() "}\n" "\n"; } - + if (mUsesMod3v) { out << "float3 mod(float3 x, float3 y)\n" @@ -1039,66 +1401,89 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) { TInfoSinkBase &out = mBody; - TString name = node->getSymbol(); - - if (name == "gl_FragColor") - { - out << "gl_Color[0]"; - mUsesFragColor = true; - } - else if (name == "gl_FragData") + // Handle accessing std140 structs by value + if (mFlaggedStructMappedNames.count(node) > 0) { - out << "gl_Color"; - mUsesFragData = true; + out << mFlaggedStructMappedNames[node]; + return; } - else if (name == "gl_DepthRange") + + TString name = node->getSymbol(); + + if (name == "gl_DepthRange") { mUsesDepthRange = true; out << name; } - else if (name == "gl_FragCoord") - { - mUsesFragCoord = true; - out << name; - } - else if (name == "gl_PointCoord") - { - mUsesPointCoord = true; - out << name; - } - else if (name == "gl_FrontFacing") - { - mUsesFrontFacing = true; - out << name; - } - else if (name == "gl_PointSize") - { - mUsesPointSize = true; - out << name; - } - else if (name == "gl_FragDepthEXT") - { - mUsesFragDepth = true; - out << "gl_Depth"; - } else { TQualifier qualifier = node->getQualifier(); if (qualifier == EvqUniform) { - mReferencedUniforms[name] = node; - out << decorateUniform(name, node->getType()); + const TType& nodeType = node->getType(); + const TInterfaceBlock* interfaceBlock = nodeType.getInterfaceBlock(); + + if (interfaceBlock) + { + mReferencedInterfaceBlocks[interfaceBlock->name()] = node; + } + else + { + mReferencedUniforms[name] = node; + } + + out << DecorateUniform(name, nodeType); } - else if (qualifier == EvqAttribute) + else if (qualifier == EvqAttribute || qualifier == EvqVertexIn) { mReferencedAttributes[name] = node; - out << decorate(name); + out << Decorate(name); } - else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn) + else if (IsVarying(qualifier)) { mReferencedVaryings[name] = node; - out << decorate(name); + out << Decorate(name); + } + else if (qualifier == EvqFragmentOut) + { + mReferencedOutputVariables[name] = node; + out << "out_" << name; + } + else if (qualifier == EvqFragColor) + { + out << "gl_Color[0]"; + mUsesFragColor = true; + } + else if (qualifier == EvqFragData) + { + out << "gl_Color"; + mUsesFragData = true; + } + else if (qualifier == EvqFragCoord) + { + mUsesFragCoord = true; + out << name; + } + else if (qualifier == EvqPointCoord) + { + mUsesPointCoord = true; + out << name; + } + else if (qualifier == EvqFrontFacing) + { + mUsesFrontFacing = true; + out << name; + } + else if (qualifier == EvqPointSize) + { + mUsesPointSize = true; + out << name; + } + else if (name == "gl_FragDepthEXT") + { + mUsesFragDepth = true; + out << "gl_Depth"; } else if (qualifier == EvqInternal) { @@ -1106,15 +1491,27 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) } else { - out << decorate(name); + out << Decorate(name); } } } +void OutputHLSL::visitRaw(TIntermRaw *node) +{ + mBody << node->getRawText(); +} + bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) { TInfoSinkBase &out = mBody; + // Handle accessing std140 structs by value + if (mFlaggedStructMappedNames.count(node) > 0) + { + out << mFlaggedStructMappedNames[node]; + return false; + } + switch (node->getOp()) { case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break; @@ -1165,7 +1562,7 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) { out << " = mul("; node->getLeft()->traverse(this); - out << ", transpose("; + out << ", transpose("; } else { @@ -1181,7 +1578,7 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) { out << " = mul("; node->getLeft()->traverse(this); - out << ", "; + out << ", "; } else { @@ -1189,15 +1586,49 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) } break; case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break; - case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break; - case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break; + case EOpIndexDirect: + { + const TType& leftType = node->getLeft()->getType(); + if (leftType.isInterfaceBlock()) + { + if (visit == PreVisit) + { + TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock(); + const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0); + mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode(); + out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex); + return false; + } + } + else + { + outputTriplet(visit, "", "[", "]"); + } + } + break; + case EOpIndexIndirect: + // We do not currently support indirect references to interface blocks + ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock); + outputTriplet(visit, "", "[", "]"); + break; case EOpIndexDirectStruct: if (visit == InVisit) { const TStructure* structure = node->getLeft()->getType().getStruct(); const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion(); const TField* field = structure->fields()[index->getIConst(0)]; - out << "." + decorateField(field->name(), node->getLeft()->getType()); + out << "." + DecorateField(field->name(), *structure); + + return false; + } + break; + case EOpIndexDirectInterfaceBlock: + if (visit == InVisit) + { + const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); + const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion(); + const TField* field = interfaceBlock->fields()[index->getIConst(0)]; + out << "." + Decorate(field->name()); return false; } @@ -1211,9 +1642,9 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) if (swizzle) { - TIntermSequence &sequence = swizzle->getSequence(); + TIntermSequence *sequence = swizzle->getSequence(); - for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) { TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); @@ -1266,16 +1697,17 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) out << "!("; } - const TFieldList &fields = node->getLeft()->getType().getStruct()->fields(); + const TStructure &structure = *node->getLeft()->getType().getStruct(); + const TFieldList &fields = structure.fields(); for (size_t i = 0; i < fields.size(); i++) { const TField *field = fields[i]; node->getLeft()->traverse(this); - out << "." + decorateField(field->name(), node->getLeft()->getType()) + " == "; + out << "." + DecorateField(field->name(), structure) + " == "; node->getRight()->traverse(this); - out << "." + decorateField(field->name(), node->getLeft()->getType()); + out << "." + DecorateField(field->name(), structure); if (i < fields.size() - 1) { @@ -1346,46 +1778,13 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) { switch (node->getOp()) { - case EOpNegative: outputTriplet(visit, "(-", "", ")"); break; - case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break; - case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break; - case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break; - case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break; - case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break; - case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break; - case EOpConvIntToBool: - case EOpConvFloatToBool: - switch (node->getOperand()->getType().getNominalSize()) - { - case 1: outputTriplet(visit, "bool(", "", ")"); break; - case 2: outputTriplet(visit, "bool2(", "", ")"); break; - case 3: outputTriplet(visit, "bool3(", "", ")"); break; - case 4: outputTriplet(visit, "bool4(", "", ")"); break; - default: UNREACHABLE(); - } - break; - case EOpConvBoolToFloat: - case EOpConvIntToFloat: - switch (node->getOperand()->getType().getNominalSize()) - { - case 1: outputTriplet(visit, "float(", "", ")"); break; - case 2: outputTriplet(visit, "float2(", "", ")"); break; - case 3: outputTriplet(visit, "float3(", "", ")"); break; - case 4: outputTriplet(visit, "float4(", "", ")"); break; - default: UNREACHABLE(); - } - break; - case EOpConvFloatToInt: - case EOpConvBoolToInt: - switch (node->getOperand()->getType().getNominalSize()) - { - case 1: outputTriplet(visit, "int(", "", ")"); break; - case 2: outputTriplet(visit, "int2(", "", ")"); break; - case 3: outputTriplet(visit, "int3(", "", ")"); break; - case 4: outputTriplet(visit, "int4(", "", ")"); break; - default: UNREACHABLE(); - } - break; + case EOpNegative: outputTriplet(visit, "(-", "", ")"); break; + case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break; + case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break; + case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break; + case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break; + case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break; + case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break; case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break; case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break; case EOpSin: outputTriplet(visit, "sin(", "", ")"); break; @@ -1457,20 +1856,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) { outputLineDirective(node->getLine().first_line); out << "{\n"; - - mScopeDepth++; - - if (mScopeBracket.size() < mScopeDepth) - { - mScopeBracket.push_back(0); // New scope level - } - else - { - mScopeBracket[mScopeDepth - 1]++; // New scope at existing level - } } - for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++) + for (TIntermSequence::iterator sit = node->getSequence()->begin(); sit != node->getSequence()->end(); sit++) { outputLineDirective((*sit)->getLine().first_line); @@ -1483,8 +1871,6 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) { outputLineDirective(node->getLine().last_line); out << "}\n"; - - mScopeDepth--; } return false; @@ -1492,14 +1878,16 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case EOpDeclaration: if (visit == PreVisit) { - TIntermSequence &sequence = node->getSequence(); - TIntermTyped *variable = sequence[0]->getAsTyped(); + TIntermSequence *sequence = node->getSequence(); + TIntermTyped *variable = (*sequence)[0]->getAsTyped(); if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal)) { - if (variable->getType().getStruct()) + TStructure *structure = variable->getType().getStruct(); + + if (structure) { - addConstructor(variable->getType(), scopedStruct(variable->getType().getStruct()->name()), NULL); + mStructureHLSL->addConstructor(variable->getType(), StructNameString(*structure), NULL); } if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration @@ -1509,16 +1897,16 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) out << "static "; } - out << typeString(variable->getType()) + " "; + out << TypeString(variable->getType()) + " "; - for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) { TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); if (symbol) { symbol->traverse(this); - out << arrayString(symbol->getType()); + out << ArrayString(symbol->getType()); out << " = " + initializer(symbol->getType()); } else @@ -1526,7 +1914,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) (*sit)->traverse(this); } - if (*sit != sequence.back()) + if (*sit != sequence->back()) { out << ", "; } @@ -1538,9 +1926,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) } else UNREACHABLE(); } - else if (variable && (variable->getQualifier() == EvqVaryingOut || variable->getQualifier() == EvqInvariantVaryingOut)) + else if (variable && IsVaryingOut(variable->getQualifier())) { - for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) { TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); @@ -1566,19 +1954,19 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case EOpPrototype: if (visit == PreVisit) { - out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "("); + out << TypeString(node->getType()) << " " << Decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "("); - TIntermSequence &arguments = node->getSequence(); + TIntermSequence *arguments = node->getSequence(); - for (unsigned int i = 0; i < arguments.size(); i++) + for (unsigned int i = 0; i < arguments->size(); i++) { - TIntermSymbol *symbol = arguments[i]->getAsSymbolNode(); + TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode(); if (symbol) { out << argumentString(symbol); - if (i < arguments.size() - 1) + if (i < arguments->size() - 1) { out << ", "; } @@ -1604,7 +1992,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) { TString name = TFunction::unmangleName(node->getName()); - out << typeString(node->getType()) << " "; + out << TypeString(node->getType()) << " "; if (name == "main") { @@ -1612,26 +2000,28 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) } else { - out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "("); + out << Decorate(name) << (mOutputLod0Function ? "Lod0(" : "("); } - TIntermSequence &sequence = node->getSequence(); - TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence(); + TIntermSequence *sequence = node->getSequence(); + TIntermSequence *arguments = (*sequence)[0]->getAsAggregate()->getSequence(); - for (unsigned int i = 0; i < arguments.size(); i++) + for (unsigned int i = 0; i < arguments->size(); i++) { - TIntermSymbol *symbol = arguments[i]->getAsSymbolNode(); + TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode(); if (symbol) { - if (symbol->getType().getStruct()) + TStructure *structure = symbol->getType().getStruct(); + + if (structure) { - addConstructor(symbol->getType(), scopedStruct(symbol->getType().getStruct()->name()), NULL); + mStructureHLSL->addConstructor(symbol->getType(), StructNameString(*structure), NULL); } out << argumentString(symbol); - if (i < arguments.size() - 1) + if (i < arguments->size() - 1) { out << ", "; } @@ -1641,169 +2031,160 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) out << ")\n" "{\n"; - - if (sequence.size() > 1) + + if (sequence->size() > 1) { mInsideFunction = true; - sequence[1]->traverse(this); + (*sequence)[1]->traverse(this); mInsideFunction = false; } - + out << "}\n"; if (mContainsLoopDiscontinuity && !mOutputLod0Function) { if (name != "main") { - mOutputLod0Function = true; - node->traverse(this); - mOutputLod0Function = false; + mOutputLod0Function = true; + node->traverse(this); + mOutputLod0Function = false; + } + } + + return false; + } + break; + case EOpFunctionCall: + { + TString name = TFunction::unmangleName(node->getName()); + bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function; + TIntermSequence *arguments = node->getSequence(); + + if (node->isUserDefined()) + { + out << Decorate(name) << (lod0 ? "Lod0(" : "("); + } + else + { + TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType(); + + TextureFunction textureFunction; + textureFunction.sampler = samplerType; + textureFunction.coords = (*arguments)[1]->getAsTyped()->getNominalSize(); + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.proj = false; + textureFunction.offset = false; + + if (name == "texture2D" || name == "textureCube" || name == "texture") + { + textureFunction.method = TextureFunction::IMPLICIT; + } + else if (name == "texture2DProj" || name == "textureProj") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.proj = true; + } + else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" || + name == "texture2DLodEXT" || name == "textureCubeLodEXT") + { + textureFunction.method = TextureFunction::LOD; + } + else if (name == "texture2DProjLod" || name == "textureProjLod" || name == "texture2DProjLodEXT") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.proj = true; + } + else if (name == "textureSize") + { + textureFunction.method = TextureFunction::SIZE; + } + else if (name == "textureOffset") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.offset = true; + } + else if (name == "textureProjOffset") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.offset = true; + textureFunction.proj = true; + } + else if (name == "textureLodOffset") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.offset = true; + } + else if (name == "textureProjLodOffset") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.proj = true; + textureFunction.offset = true; + } + else if (name == "texelFetch") + { + textureFunction.method = TextureFunction::FETCH; + } + else if (name == "texelFetchOffset") + { + textureFunction.method = TextureFunction::FETCH; + textureFunction.offset = true; + } + else if (name == "textureGrad" || name == "texture2DGradEXT") + { + textureFunction.method = TextureFunction::GRAD; + } + else if (name == "textureGradOffset") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.offset = true; } - } - - return false; - } - break; - case EOpFunctionCall: - { - TString name = TFunction::unmangleName(node->getName()); - bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function; - - if (node->isUserDefined()) - { - out << decorate(name) << (lod0 ? "Lod0(" : "("); - } - else - { - if (name == "texture2D") + else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || name == "textureCubeGradEXT") { - if (!lod0) - { - if (node->getSequence().size() == 2) - { - mUsesTexture2D = true; - } - else if (node->getSequence().size() == 3) - { - mUsesTexture2D_bias = true; - } - else UNREACHABLE(); - - out << "gl_texture2D("; - } - else - { - if (node->getSequence().size() == 2) - { - mUsesTexture2DLod0 = true; - } - else if (node->getSequence().size() == 3) - { - mUsesTexture2DLod0_bias = true; - } - else UNREACHABLE(); - - out << "gl_texture2DLod0("; - } + textureFunction.method = TextureFunction::GRAD; + textureFunction.proj = true; } - else if (name == "texture2DProj") + else if (name == "textureProjGradOffset") { - if (!lod0) - { - if (node->getSequence().size() == 2) - { - mUsesTexture2DProj = true; - } - else if (node->getSequence().size() == 3) - { - mUsesTexture2DProj_bias = true; - } - else UNREACHABLE(); - - out << "gl_texture2DProj("; - } - else - { - if (node->getSequence().size() == 2) - { - mUsesTexture2DProjLod0 = true; - } - else if (node->getSequence().size() == 3) - { - mUsesTexture2DProjLod0_bias = true; - } - else UNREACHABLE(); - - out << "gl_texture2DProjLod0("; - } + textureFunction.method = TextureFunction::GRAD; + textureFunction.proj = true; + textureFunction.offset = true; } - else if (name == "textureCube") + else UNREACHABLE(); + + if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument { - if (!lod0) - { - if (node->getSequence().size() == 2) - { - mUsesTextureCube = true; - } - else if (node->getSequence().size() == 3) - { - mUsesTextureCube_bias = true; - } - else UNREACHABLE(); + unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments - out << "gl_textureCube("; + if (textureFunction.offset) + { + mandatoryArgumentCount++; } - else + + bool bias = (arguments->size() > mandatoryArgumentCount); // Bias argument is optional + + if (lod0 || mContext.shaderType == GL_VERTEX_SHADER) { - if (node->getSequence().size() == 2) + if (bias) { - mUsesTextureCubeLod0 = true; + textureFunction.method = TextureFunction::LOD0BIAS; } - else if (node->getSequence().size() == 3) + else { - mUsesTextureCubeLod0_bias = true; + textureFunction.method = TextureFunction::LOD0; } - else UNREACHABLE(); - - out << "gl_textureCubeLod0("; } - } - else if (name == "texture2DLod") - { - if (node->getSequence().size() == 3) + else if (bias) { - mUsesTexture2DLod = true; + textureFunction.method = TextureFunction::BIAS; } - else UNREACHABLE(); - - out << "gl_texture2DLod("; } - else if (name == "texture2DProjLod") - { - if (node->getSequence().size() == 3) - { - mUsesTexture2DProjLod = true; - } - else UNREACHABLE(); - out << "gl_texture2DProjLod("; - } - else if (name == "textureCubeLod") - { - if (node->getSequence().size() == 3) - { - mUsesTextureCubeLod = true; - } - else UNREACHABLE(); + mUsesTexture.insert(textureFunction); - out << "gl_textureCubeLod("; - } - else UNREACHABLE(); + out << textureFunction.name(); } - TIntermSequence &arguments = node->getSequence(); - - for (TIntermSequence::iterator arg = arguments.begin(); arg != arguments.end(); arg++) + for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++) { if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType())) { @@ -1814,7 +2195,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) (*arg)->traverse(this); - if (arg < arguments.end() - 1) + if (arg < arguments->end() - 1) { out << ", "; } @@ -1825,70 +2206,32 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) return false; } break; - case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break; - case EOpConstructFloat: - addConstructor(node->getType(), "vec1", &node->getSequence()); - outputTriplet(visit, "vec1(", "", ")"); - break; - case EOpConstructVec2: - addConstructor(node->getType(), "vec2", &node->getSequence()); - outputTriplet(visit, "vec2(", ", ", ")"); - break; - case EOpConstructVec3: - addConstructor(node->getType(), "vec3", &node->getSequence()); - outputTriplet(visit, "vec3(", ", ", ")"); - break; - case EOpConstructVec4: - addConstructor(node->getType(), "vec4", &node->getSequence()); - outputTriplet(visit, "vec4(", ", ", ")"); - break; - case EOpConstructBool: - addConstructor(node->getType(), "bvec1", &node->getSequence()); - outputTriplet(visit, "bvec1(", "", ")"); - break; - case EOpConstructBVec2: - addConstructor(node->getType(), "bvec2", &node->getSequence()); - outputTriplet(visit, "bvec2(", ", ", ")"); - break; - case EOpConstructBVec3: - addConstructor(node->getType(), "bvec3", &node->getSequence()); - outputTriplet(visit, "bvec3(", ", ", ")"); - break; - case EOpConstructBVec4: - addConstructor(node->getType(), "bvec4", &node->getSequence()); - outputTriplet(visit, "bvec4(", ", ", ")"); - break; - case EOpConstructInt: - addConstructor(node->getType(), "ivec1", &node->getSequence()); - outputTriplet(visit, "ivec1(", "", ")"); - break; - case EOpConstructIVec2: - addConstructor(node->getType(), "ivec2", &node->getSequence()); - outputTriplet(visit, "ivec2(", ", ", ")"); - break; - case EOpConstructIVec3: - addConstructor(node->getType(), "ivec3", &node->getSequence()); - outputTriplet(visit, "ivec3(", ", ", ")"); - break; - case EOpConstructIVec4: - addConstructor(node->getType(), "ivec4", &node->getSequence()); - outputTriplet(visit, "ivec4(", ", ", ")"); - break; - case EOpConstructMat2: - addConstructor(node->getType(), "mat2", &node->getSequence()); - outputTriplet(visit, "mat2(", ", ", ")"); - break; - case EOpConstructMat3: - addConstructor(node->getType(), "mat3", &node->getSequence()); - outputTriplet(visit, "mat3(", ", ", ")"); - break; - case EOpConstructMat4: - addConstructor(node->getType(), "mat4", &node->getSequence()); - outputTriplet(visit, "mat4(", ", ", ")"); - break; + case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break; + case EOpConstructFloat: outputConstructor(visit, node->getType(), "vec1", node->getSequence()); break; + case EOpConstructVec2: outputConstructor(visit, node->getType(), "vec2", node->getSequence()); break; + case EOpConstructVec3: outputConstructor(visit, node->getType(), "vec3", node->getSequence()); break; + case EOpConstructVec4: outputConstructor(visit, node->getType(), "vec4", node->getSequence()); break; + case EOpConstructBool: outputConstructor(visit, node->getType(), "bvec1", node->getSequence()); break; + case EOpConstructBVec2: outputConstructor(visit, node->getType(), "bvec2", node->getSequence()); break; + case EOpConstructBVec3: outputConstructor(visit, node->getType(), "bvec3", node->getSequence()); break; + case EOpConstructBVec4: outputConstructor(visit, node->getType(), "bvec4", node->getSequence()); break; + case EOpConstructInt: outputConstructor(visit, node->getType(), "ivec1", node->getSequence()); break; + case EOpConstructIVec2: outputConstructor(visit, node->getType(), "ivec2", node->getSequence()); break; + case EOpConstructIVec3: outputConstructor(visit, node->getType(), "ivec3", node->getSequence()); break; + case EOpConstructIVec4: outputConstructor(visit, node->getType(), "ivec4", node->getSequence()); break; + case EOpConstructUInt: outputConstructor(visit, node->getType(), "uvec1", node->getSequence()); break; + case EOpConstructUVec2: outputConstructor(visit, node->getType(), "uvec2", node->getSequence()); break; + case EOpConstructUVec3: outputConstructor(visit, node->getType(), "uvec3", node->getSequence()); break; + case EOpConstructUVec4: outputConstructor(visit, node->getType(), "uvec4", node->getSequence()); break; + case EOpConstructMat2: outputConstructor(visit, node->getType(), "mat2", node->getSequence()); break; + case EOpConstructMat3: outputConstructor(visit, node->getType(), "mat3", node->getSequence()); break; + case EOpConstructMat4: outputConstructor(visit, node->getType(), "mat4", node->getSequence()); break; case EOpConstructStruct: - addConstructor(node->getType(), scopedStruct(node->getType().getStruct()->name()), &node->getSequence()); - outputTriplet(visit, structLookup(node->getType().getStruct()->name()) + "_ctor(", ", ", ")"); + { + const TString &structName = StructNameString(*node->getType().getStruct()); + mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence()); + outputTriplet(visit, structName + "_ctor(", ", ", ")"); + } break; case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; @@ -1899,8 +2242,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case EOpMod: { // We need to look at the number of components in both arguments - switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10 - + node->getSequence()[1]->getAsTyped()->getNominalSize()) + const int modValue = (*node->getSequence())[0]->getAsTyped()->getNominalSize() * 10 + + (*node->getSequence())[1]->getAsTyped()->getNominalSize(); + switch (modValue) { case 11: mUsesMod1 = true; break; case 22: mUsesMod2v = true; break; @@ -1917,8 +2261,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) break; case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break; case EOpAtan: - ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator - switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) + ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator + switch ((*node->getSequence())[0]->getAsTyped()->getNominalSize()) { case 1: mUsesAtan2_1 = true; break; case 2: mUsesAtan2_2 = true; break; @@ -1939,7 +2283,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break; case EOpFaceForward: { - switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument + switch ((*node->getSequence())[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument { case 1: mUsesFaceforward1 = true; break; case 2: mUsesFaceforward2 = true; break; @@ -1947,7 +2291,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case 4: mUsesFaceforward4 = true; break; default: UNREACHABLE(); } - + outputTriplet(visit, "faceforward(", ", ", ")"); } break; @@ -1977,7 +2321,7 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) node->getCondition()->traverse(this); out << ")\n"; - + outputLineDirective(node->getLine().first_line); out << "{\n"; @@ -2028,6 +2372,8 @@ void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node) bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) { + mNestedLoopDepth++; + bool wasDiscontinuous = mInsideDiscontinuousLoop; if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop) @@ -2039,6 +2385,9 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) { if (handleExcessiveLoop(node)) { + mInsideDiscontinuousLoop = wasDiscontinuous; + mNestedLoopDepth--; + return false; } } @@ -2055,7 +2404,7 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) else { out << "{for("; - + if (node->getInit()) { node->getInit()->traverse(this); @@ -2076,7 +2425,7 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) } out << ")\n"; - + outputLineDirective(node->getLine().first_line); out << "{\n"; } @@ -2102,6 +2451,7 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) out << "}\n"; mInsideDiscontinuousLoop = wasDiscontinuous; + mNestedLoopDepth--; return false; } @@ -2118,6 +2468,11 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) case EOpBreak: if (visit == PreVisit) { + if (mNestedLoopDepth > 1) + { + mUsesNestedBreak = true; + } + if (mExcessiveLoopIndex) { out << "{Break"; @@ -2179,7 +2534,7 @@ bool OutputHLSL::isSingleStatement(TIntermNode *node) } else { - for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++) + for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++) { if (!isSingleStatement(*sit)) { @@ -2216,8 +2571,8 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) if (init) { - TIntermSequence &sequence = init->getSequence(); - TIntermTyped *variable = sequence[0]->getAsTyped(); + TIntermSequence *sequence = init->getSequence(); + TIntermTyped *variable = (*sequence)[0]->getAsTyped(); if (variable && variable->getQualifier() == EvqTemporary) { @@ -2230,7 +2585,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) if (symbol && constant) { - if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1) + if (constant->getBasicType() == EbtInt && constant->isScalar()) { index = symbol; initial = constant->getIConst(0); @@ -2245,14 +2600,14 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) if (index != NULL && node->getCondition()) { TIntermBinary *test = node->getCondition()->getAsBinaryNode(); - + if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId()) { TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion(); if (constant) { - if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1) + if (constant->getBasicType() == EbtInt && constant->isScalar()) { comparator = test->getOp(); limit = constant->getIConst(0); @@ -2266,7 +2621,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) { TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode(); TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode(); - + if (binaryTerminal) { TOperator op = binaryTerminal->getOp(); @@ -2274,7 +2629,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) if (constant) { - if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1) + if (constant->getBasicType() == EbtInt && constant->isScalar()) { int value = constant->getIConst(0); @@ -2346,7 +2701,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) { mExcessiveLoopIndex = NULL; // Stops setting the Break flag } - + // for(int index = initial; index < clampedLimit; index += increment) out << "for("; @@ -2364,7 +2719,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) out << " += "; out << increment; out << ")\n"; - + outputLineDirective(node->getLine().first_line); out << "{\n"; @@ -2385,449 +2740,130 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) initial += MAX_LOOP_ITERATIONS * increment; iterations -= MAX_LOOP_ITERATIONS; - } - - out << "}"; - - mExcessiveLoopIndex = restoreIndex; - - return true; - } - else UNIMPLEMENTED(); - } - - return false; // Not handled as an excessive loop -} - -void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString) -{ - TInfoSinkBase &out = mBody; - - if (visit == PreVisit) - { - out << preString; - } - else if (visit == InVisit) - { - out << inString; - } - else if (visit == PostVisit) - { - out << postString; - } -} - -void OutputHLSL::outputLineDirective(int line) -{ - if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0)) - { - mBody << "\n"; - mBody << "#line " << line; - - if (mContext.sourcePath) - { - mBody << " \"" << mContext.sourcePath << "\""; - } - - mBody << "\n"; - } -} - -TString OutputHLSL::argumentString(const TIntermSymbol *symbol) -{ - TQualifier qualifier = symbol->getQualifier(); - const TType &type = symbol->getType(); - TString name = symbol->getSymbol(); - - if (name.empty()) // HLSL demands named arguments, also for prototypes - { - name = "x" + str(mUniqueIndex++); - } - else - { - name = decorate(name); - } - - if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) - { - return qualifierString(qualifier) + " " + textureString(type) + " texture_" + name + arrayString(type) + ", " + - qualifierString(qualifier) + " SamplerState sampler_" + name + arrayString(type); - } - - return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type); -} - -TString OutputHLSL::qualifierString(TQualifier qualifier) -{ - switch(qualifier) - { - case EvqIn: return "in"; - case EvqOut: return "out"; - case EvqInOut: return "inout"; - case EvqConstReadOnly: return "const"; - default: UNREACHABLE(); - } - - return ""; -} - -TString OutputHLSL::typeString(const TType &type) -{ - if (type.getBasicType() == EbtStruct) - { - const TString& typeName = type.getStruct()->name(); - if (typeName != "") - { - return structLookup(typeName); - } - else // Nameless structure, define in place - { - const TFieldList &fields = type.getStruct()->fields(); - - TString string = "struct\n" - "{\n"; - - for (unsigned int i = 0; i < fields.size(); i++) - { - const TField *field = fields[i]; - - string += " " + typeString(*field->type()) + " " + decorate(field->name()) + arrayString(*field->type()) + ";\n"; - } - - string += "} "; - - return string; - } - } - else if (type.isMatrix()) - { - switch (type.getNominalSize()) - { - case 2: return "float2x2"; - case 3: return "float3x3"; - case 4: return "float4x4"; - } - } - else - { - switch (type.getBasicType()) - { - case EbtFloat: - switch (type.getNominalSize()) - { - case 1: return "float"; - case 2: return "float2"; - case 3: return "float3"; - case 4: return "float4"; - } - case EbtInt: - switch (type.getNominalSize()) - { - case 1: return "int"; - case 2: return "int2"; - case 3: return "int3"; - case 4: return "int4"; - } - case EbtBool: - switch (type.getNominalSize()) - { - case 1: return "bool"; - case 2: return "bool2"; - case 3: return "bool3"; - case 4: return "bool4"; - } - case EbtVoid: - return "void"; - case EbtSampler2D: - return "sampler2D"; - case EbtSamplerCube: - return "samplerCUBE"; - case EbtSamplerExternalOES: - return "sampler2D"; - default: - break; - } - } - - UNREACHABLE(); - return ""; -} - -TString OutputHLSL::textureString(const TType &type) -{ - switch (type.getBasicType()) - { - case EbtSampler2D: - return "Texture2D"; - case EbtSamplerCube: - return "TextureCube"; - case EbtSamplerExternalOES: - return "Texture2D"; - default: - break; - } - - UNREACHABLE(); - return ""; -} - -TString OutputHLSL::arrayString(const TType &type) -{ - if (!type.isArray()) - { - return ""; - } - - return "[" + str(type.getArraySize()) + "]"; -} - -TString OutputHLSL::initializer(const TType &type) -{ - TString string; - - size_t size = type.getObjectSize(); - for (size_t component = 0; component < size; component++) - { - string += "0"; - - if (component + 1 < size) - { - string += ", "; - } - } - - return "{" + string + "}"; -} - -void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters) -{ - if (name == "") - { - return; // Nameless structures don't have constructors - } - - if (type.getStruct() && mStructNames.find(decorate(name)) != mStructNames.end()) - { - return; // Already added - } - - TType ctorType = type; - ctorType.clearArrayness(); - ctorType.setPrecision(EbpHigh); - ctorType.setQualifier(EvqTemporary); - - TString ctorName = type.getStruct() ? decorate(name) : name; - - typedef std::vector ParameterArray; - ParameterArray ctorParameters; - - if (type.getStruct()) - { - mStructNames.insert(decorate(name)); - - TString structure; - structure += "struct " + decorate(name) + "\n" - "{\n"; + } - const TFieldList &fields = type.getStruct()->fields(); + out << "}"; - for (unsigned int i = 0; i < fields.size(); i++) - { - const TField *field = fields[i]; + mExcessiveLoopIndex = restoreIndex; - structure += " " + typeString(*field->type()) + " " + decorateField(field->name(), type) + arrayString(*field->type()) + ";\n"; + return true; } + else UNIMPLEMENTED(); + } - structure += "};\n"; + return false; // Not handled as an excessive loop +} - if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end()) - { - mStructDeclarations.push_back(structure); - } +void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString) +{ + TInfoSinkBase &out = mBody; - for (unsigned int i = 0; i < fields.size(); i++) - { - ctorParameters.push_back(*fields[i]->type()); - } - } - else if (parameters) + if (visit == PreVisit) { - for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++) - { - ctorParameters.push_back((*parameter)->getAsTyped()->getType()); - } + out << preString; } - else UNREACHABLE(); - - TString constructor; - - if (ctorType.getStruct()) + else if (visit == InVisit) { - constructor += ctorName + " " + ctorName + "_ctor("; + out << inString; } - else // Built-in type + else if (visit == PostVisit) { - constructor += typeString(ctorType) + " " + ctorName + "("; + out << postString; } +} - for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) +void OutputHLSL::outputLineDirective(int line) +{ + if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0)) { - const TType &type = ctorParameters[parameter]; - - constructor += typeString(type) + " x" + str(parameter) + arrayString(type); + mBody << "\n"; + mBody << "#line " << line; - if (parameter < ctorParameters.size() - 1) + if (mContext.sourcePath) { - constructor += ", "; + mBody << " \"" << mContext.sourcePath << "\""; } + + mBody << "\n"; } +} - constructor += ")\n" - "{\n"; +TString OutputHLSL::argumentString(const TIntermSymbol *symbol) +{ + TQualifier qualifier = symbol->getQualifier(); + const TType &type = symbol->getType(); + TString name = symbol->getSymbol(); - if (ctorType.getStruct()) + if (name.empty()) // HLSL demands named arguments, also for prototypes { - constructor += " " + ctorName + " structure = {"; + name = "x" + str(mUniqueIndex++); } else { - constructor += " return " + typeString(ctorType) + "("; + name = Decorate(name); } - if (ctorType.isMatrix() && ctorParameters.size() == 1) + if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) { - int dim = ctorType.getNominalSize(); - const TType ¶meter = ctorParameters[0]; + return QualifierString(qualifier) + " " + TextureString(type) + " texture_" + name + ArrayString(type) + ", " + + QualifierString(qualifier) + " " + SamplerString(type) + " sampler_" + name + ArrayString(type); + } - if (parameter.isScalar()) - { - for (int row = 0; row < dim; row++) - { - for (int col = 0; col < dim; col++) - { - constructor += TString((row == col) ? "x0" : "0.0"); - - if (row < dim - 1 || col < dim - 1) - { - constructor += ", "; - } - } - } - } - else if (parameter.isMatrix()) - { - for (int row = 0; row < dim; row++) - { - for (int col = 0; col < dim; col++) - { - if (row < parameter.getNominalSize() && col < parameter.getNominalSize()) - { - constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]"; - } - else - { - constructor += TString((row == col) ? "1.0" : "0.0"); - } + return QualifierString(qualifier) + " " + TypeString(type) + " " + name + ArrayString(type); +} - if (row < dim - 1 || col < dim - 1) - { - constructor += ", "; - } - } - } - } - else UNREACHABLE(); - } - else +TString OutputHLSL::initializer(const TType &type) +{ + TString string; + + size_t size = type.getObjectSize(); + for (size_t component = 0; component < size; component++) { - size_t remainingComponents = ctorType.getObjectSize(); - size_t parameterIndex = 0; + string += "0"; - while (remainingComponents > 0) + if (component + 1 < size) { - const TType ¶meter = ctorParameters[parameterIndex]; - const size_t parameterSize = parameter.getObjectSize(); - bool moreParameters = parameterIndex + 1 < ctorParameters.size(); - - constructor += "x" + str(parameterIndex); + string += ", "; + } + } - if (parameter.isScalar()) - { - ASSERT(parameterSize <= remainingComponents); - remainingComponents -= parameterSize; - } - else if (parameter.isVector()) - { - if (remainingComponents == parameterSize || moreParameters) - { - ASSERT(parameterSize <= remainingComponents); - remainingComponents -= parameterSize; - } - else if (remainingComponents < static_cast(parameter.getNominalSize())) - { - switch (remainingComponents) - { - case 1: constructor += ".x"; break; - case 2: constructor += ".xy"; break; - case 3: constructor += ".xyz"; break; - case 4: constructor += ".xyzw"; break; - default: UNREACHABLE(); - } + return "{" + string + "}"; +} - remainingComponents = 0; - } - else UNREACHABLE(); - } - else if (parameter.isMatrix() || parameter.getStruct()) - { - ASSERT(remainingComponents == parameterSize || moreParameters); - ASSERT(parameterSize <= remainingComponents); - - remainingComponents -= parameterSize; - } - else UNREACHABLE(); +void OutputHLSL::outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters) +{ + TInfoSinkBase &out = mBody; - if (moreParameters) - { - parameterIndex++; - } + if (visit == PreVisit) + { + mStructureHLSL->addConstructor(type, name, parameters); - if (remainingComponents) - { - constructor += ", "; - } - } + out << name + "("; } - - if (ctorType.getStruct()) + else if (visit == InVisit) { - constructor += "};\n" - " return structure;\n" - "}\n"; + out << ", "; } - else + else if (visit == PostVisit) { - constructor += ");\n" - "}\n"; + out << ")"; } - - mConstructors.insert(constructor); } const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion) { TInfoSinkBase &out = mBody; - if (type.getBasicType() == EbtStruct) + const TStructure* structure = type.getStruct(); + if (structure) { - out << structLookup(type.getStruct()->name()) + "_ctor("; - - const TFieldList &fields = type.getStruct()->fields(); + out << StructNameString(*structure) + "_ctor("; + + const TFieldList& fields = structure->fields(); for (size_t i = 0; i < fields.size(); i++) { const TType *fieldType = fields[i]->type(); - constUnion = writeConstantUnion(*fieldType, constUnion); if (i != fields.size() - 1) @@ -2842,10 +2878,10 @@ const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const Con { size_t size = type.getObjectSize(); bool writeType = size > 1; - + if (writeType) { - out << typeString(type) << "("; + out << TypeString(type) << "("; } for (size_t i = 0; i < size; i++, constUnion++) @@ -2854,6 +2890,7 @@ const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const Con { case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break; case EbtInt: out << constUnion->getIConst(); break; + case EbtUInt: out << constUnion->getUConst(); break; case EbtBool: out << constUnion->getBConst(); break; default: UNREACHABLE(); } @@ -2873,266 +2910,29 @@ const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const Con return constUnion; } -TString OutputHLSL::scopeString(unsigned int depthLimit) -{ - TString string; - - for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++) - { - string += "_" + str(i); - } - - return string; -} - -TString OutputHLSL::scopedStruct(const TString &typeName) -{ - if (typeName == "") - { - return typeName; - } - - return typeName + scopeString(mScopeDepth); -} - -TString OutputHLSL::structLookup(const TString &typeName) -{ - for (int depth = mScopeDepth; depth >= 0; depth--) - { - TString scopedName = decorate(typeName + scopeString(depth)); - - for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++) - { - if (*structName == scopedName) - { - return scopedName; - } - } - } - - UNREACHABLE(); // Should have found a matching constructor - - return typeName; -} - -TString OutputHLSL::decorate(const TString &string) -{ - if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0) - { - return "_" + string; - } - - return string; -} - -TString OutputHLSL::decorateUniform(const TString &string, const TType &type) -{ - if (type.getBasicType() == EbtSamplerExternalOES) - { - return "ex_" + string; - } - - return decorate(string); -} - -TString OutputHLSL::decorateField(const TString &string, const TType &structure) -{ - if (structure.getStruct()->name().compare(0, 3, "gl_") != 0) - { - return decorate(string); - } - - return string; -} - -TString OutputHLSL::registerString(TIntermSymbol *operand) -{ - ASSERT(operand->getQualifier() == EvqUniform); - - if (IsSampler(operand->getBasicType())) - { - return "s" + str(samplerRegister(operand)); - } - - return "c" + str(uniformRegister(operand)); -} - -int OutputHLSL::samplerRegister(TIntermSymbol *sampler) -{ - const TType &type = sampler->getType(); - ASSERT(IsSampler(type.getBasicType())); - - int index = mSamplerRegister; - mSamplerRegister += sampler->totalRegisterCount(); - - declareUniform(type, sampler->getSymbol(), index); - - return index; -} - -int OutputHLSL::uniformRegister(TIntermSymbol *uniform) -{ - const TType &type = uniform->getType(); - ASSERT(!IsSampler(type.getBasicType())); - - int index = mUniformRegister; - mUniformRegister += uniform->totalRegisterCount(); - - declareUniform(type, uniform->getSymbol(), index); - - return index; -} - -void OutputHLSL::declareUniform(const TType &type, const TString &name, int index) +class DeclareVaryingTraverser : public GetVariableTraverser { - TStructure *structure = type.getStruct(); - - if (!structure) - { - mActiveUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), index)); - } - else - { - const TFieldList &fields = structure->fields(); - - if (type.isArray()) - { - int elementIndex = index; - - for (int i = 0; i < type.getArraySize(); i++) - { - for (size_t j = 0; j < fields.size(); j++) - { - const TType &fieldType = *fields[j]->type(); - const TString uniformName = name + "[" + str(i) + "]." + fields[j]->name(); - declareUniform(fieldType, uniformName, elementIndex); - elementIndex += fieldType.totalRegisterCount(); - } - } - } - else - { - int fieldIndex = index; - - for (size_t i = 0; i < fields.size(); i++) - { - const TType &fieldType = *fields[i]->type(); - const TString uniformName = name + "." + fields[i]->name(); - declareUniform(fieldType, uniformName, fieldIndex); - fieldIndex += fieldType.totalRegisterCount(); - } - } - } -} + public: + DeclareVaryingTraverser(std::vector *output, + InterpolationType interpolation) + : GetVariableTraverser(output), + mInterpolation(interpolation) + {} -GLenum OutputHLSL::glVariableType(const TType &type) -{ - if (type.getBasicType() == EbtFloat) - { - if (type.isScalar()) - { - return GL_FLOAT; - } - else if (type.isVector()) - { - switch(type.getNominalSize()) - { - case 2: return GL_FLOAT_VEC2; - case 3: return GL_FLOAT_VEC3; - case 4: return GL_FLOAT_VEC4; - default: UNREACHABLE(); - } - } - else if (type.isMatrix()) - { - switch(type.getNominalSize()) - { - case 2: return GL_FLOAT_MAT2; - case 3: return GL_FLOAT_MAT3; - case 4: return GL_FLOAT_MAT4; - default: UNREACHABLE(); - } - } - else UNREACHABLE(); - } - else if (type.getBasicType() == EbtInt) - { - if (type.isScalar()) - { - return GL_INT; - } - else if (type.isVector()) - { - switch(type.getNominalSize()) - { - case 2: return GL_INT_VEC2; - case 3: return GL_INT_VEC3; - case 4: return GL_INT_VEC4; - default: UNREACHABLE(); - } - } - else UNREACHABLE(); - } - else if (type.getBasicType() == EbtBool) - { - if (type.isScalar()) - { - return GL_BOOL; - } - else if (type.isVector()) - { - switch(type.getNominalSize()) - { - case 2: return GL_BOOL_VEC2; - case 3: return GL_BOOL_VEC3; - case 4: return GL_BOOL_VEC4; - default: UNREACHABLE(); - } - } - else UNREACHABLE(); - } - else if (type.getBasicType() == EbtSampler2D) - { - return GL_SAMPLER_2D; - } - else if (type.getBasicType() == EbtSamplerCube) + private: + void visitVariable(Varying *varying) { - return GL_SAMPLER_CUBE; + varying->interpolation = mInterpolation; } - else UNREACHABLE(); - return GL_NONE; -} + InterpolationType mInterpolation; +}; -GLenum OutputHLSL::glVariablePrecision(const TType &type) +void OutputHLSL::declareVaryingToList(const TType &type, TQualifier baseTypeQualifier, + const TString &name, std::vector &fieldsOut) { - if (type.getBasicType() == EbtFloat) - { - switch (type.getPrecision()) - { - case EbpHigh: return GL_HIGH_FLOAT; - case EbpMedium: return GL_MEDIUM_FLOAT; - case EbpLow: return GL_LOW_FLOAT; - case EbpUndefined: - // Should be defined as the default precision by the parser - default: UNREACHABLE(); - } - } - else if (type.getBasicType() == EbtInt) - { - switch (type.getPrecision()) - { - case EbpHigh: return GL_HIGH_INT; - case EbpMedium: return GL_MEDIUM_INT; - case EbpLow: return GL_LOW_INT; - case EbpUndefined: - // Should be defined as the default precision by the parser - default: UNREACHABLE(); - } - } - - // Other types (boolean, sampler) don't have a precision - return GL_NONE; + DeclareVaryingTraverser traverser(&fieldsOut, GetInterpolationType(baseTypeQualifier)); + traverser.traverse(type, name); } } diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h index 3afd8e9ada..78bb741a11 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -11,16 +11,18 @@ #include #include -#define GL_APICALL -#include - +#include "angle_gl.h" #include "compiler/translator/intermediate.h" #include "compiler/translator/ParseContext.h" -#include "compiler/translator/Uniform.h" +#include "common/shadervars.h" namespace sh { class UnfoldShortCircuit; +class StructureHLSL; +class UniformHLSL; + +typedef std::map ReferencedSymbols; class OutputHLSL : public TIntermTraverser { @@ -31,22 +33,23 @@ class OutputHLSL : public TIntermTraverser void output(); TInfoSinkBase &getBodyStream(); - const ActiveUniforms &getUniforms(); + const std::vector &getUniforms(); + const std::vector &getInterfaceBlocks() const; + const std::vector &getOutputVariables() const; + const std::vector &getAttributes() const; + const std::vector &getVaryings() const; + + const std::map &getInterfaceBlockRegisterMap() const; + const std::map &getUniformRegisterMap() const; - TString typeString(const TType &type); - TString textureString(const TType &type); - static TString qualifierString(TQualifier qualifier); - static TString arrayString(const TType &type); static TString initializer(const TType &type); - static TString decorate(const TString &string); // Prepends an underscore to avoid naming clashes - static TString decorateUniform(const TString &string, const TType &type); - static TString decorateField(const TString &string, const TType &structure); protected: void header(); // Visit AST nodes and output their code to the body stream void visitSymbol(TIntermSymbol*); + void visitRaw(TIntermRaw*); void visitConstantUnion(TIntermConstantUnion*); bool visitBinary(Visit visit, TIntermBinary*); bool visitUnary(Visit visit, TIntermUnary*); @@ -63,13 +66,9 @@ class OutputHLSL : public TIntermTraverser TString argumentString(const TIntermSymbol *symbol); int vectorSize(const TType &type) const; - void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters); + void outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters); const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion); - TString scopeString(unsigned int depthLimit); - TString scopedStruct(const TString &typeName); - TString structLookup(const TString &typeName); - TParseContext &mContext; const ShShaderOutput mOutputType; UnfoldShortCircuit *mUnfoldShortCircuit; @@ -80,27 +79,44 @@ class OutputHLSL : public TIntermTraverser TInfoSinkBase mBody; TInfoSinkBase mFooter; - typedef std::map ReferencedSymbols; ReferencedSymbols mReferencedUniforms; + ReferencedSymbols mReferencedInterfaceBlocks; ReferencedSymbols mReferencedAttributes; ReferencedSymbols mReferencedVaryings; + ReferencedSymbols mReferencedOutputVariables; + + StructureHLSL *mStructureHLSL; + UniformHLSL *mUniformHLSL; + + struct TextureFunction + { + enum Method + { + IMPLICIT, // Mipmap LOD determined implicitly (standard lookup) + BIAS, + LOD, + LOD0, + LOD0BIAS, + SIZE, // textureSize() + FETCH, + GRAD + }; + + TBasicType sampler; + int coords; + bool proj; + bool offset; + Method method; + + TString name() const; + + bool operator<(const TextureFunction &rhs) const; + }; + + typedef std::set TextureFunctionSet; // Parameters determining what goes in the header output - bool mUsesTexture2D; - bool mUsesTexture2D_bias; - bool mUsesTexture2DLod; - bool mUsesTexture2DProj; - bool mUsesTexture2DProj_bias; - bool mUsesTexture2DProjLod; - bool mUsesTextureCube; - bool mUsesTextureCube_bias; - bool mUsesTextureCubeLod; - bool mUsesTexture2DLod0; - bool mUsesTexture2DLod0_bias; - bool mUsesTexture2DProjLod0; - bool mUsesTexture2DProjLod0_bias; - bool mUsesTextureCubeLod0; - bool mUsesTextureCubeLod0_bias; + TextureFunctionSet mUsesTexture; bool mUsesFragColor; bool mUsesFragData; bool mUsesDepthRange; @@ -126,42 +142,32 @@ class OutputHLSL : public TIntermTraverser bool mUsesAtan2_3; bool mUsesAtan2_4; bool mUsesDiscardRewriting; + bool mUsesNestedBreak; int mNumRenderTargets; - typedef std::set Constructors; - Constructors mConstructors; - - typedef std::set StructNames; - StructNames mStructNames; - - typedef std::list StructDeclarations; - StructDeclarations mStructDeclarations; - - typedef std::vector ScopeBracket; - ScopeBracket mScopeBracket; - unsigned int mScopeDepth; - int mUniqueIndex; // For creating unique names bool mContainsLoopDiscontinuity; bool mOutputLod0Function; bool mInsideDiscontinuousLoop; + int mNestedLoopDepth; TIntermSymbol *mExcessiveLoopIndex; - int mUniformRegister; - int mSamplerRegister; + void declareVaryingToList(const TType &type, TQualifier baseTypeQualifier, const TString &name, std::vector& fieldsOut); - TString registerString(TIntermSymbol *operand); - int samplerRegister(TIntermSymbol *sampler); - int uniformRegister(TIntermSymbol *uniform); - void declareUniform(const TType &type, const TString &name, int index); - static GLenum glVariableType(const TType &type); - static GLenum glVariablePrecision(const TType &type); + TString structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName); - ActiveUniforms mActiveUniforms; + std::vector mActiveOutputVariables; + std::vector mActiveAttributes; + std::vector mActiveVaryings; + std::map mFlaggedStructMappedNames; + std::map mFlaggedStructOriginalNames; + + void makeFlaggedStructMaps(const std::vector &flaggedStructs); }; + } #endif // COMPILER_OUTPUTHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp index 1a1e0d140c..605612ac37 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -115,7 +115,7 @@ bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TV // Look at a '.' field selector string and change it into offsets // for a matrix. // -bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, const TSourceLoc& line) +bool TParseContext::parseMatrixFields(const TString& compString, int matCols, int matRows, TMatrixFields& fields, const TSourceLoc& line) { fields.wholeRow = false; fields.wholeCol = false; @@ -151,7 +151,7 @@ bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TM fields.col = compString[1] - '0'; } - if (fields.row >= matSize || fields.col >= matSize) { + if (fields.row >= matRows || fields.col >= matCols) { error(line, "matrix field selection out of range", compString.c_str()); return false; } @@ -277,6 +277,7 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIn case EOpIndexDirect: case EOpIndexIndirect: case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: return lValueErrorCheck(line, op, binaryNode->getLeft()); case EOpVectorSwizzle: errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); @@ -285,21 +286,21 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIn TIntermTyped* rightNode = binaryNode->getRight(); TIntermAggregate *aggrNode = rightNode->getAsAggregate(); - - for (TIntermSequence::iterator p = aggrNode->getSequence().begin(); - p != aggrNode->getSequence().end(); p++) { + + for (TIntermSequence::iterator p = aggrNode->getSequence()->begin(); + p != aggrNode->getSequence()->end(); p++) { int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0); - offset[value]++; + offset[value]++; if (offset[value] > 1) { error(line, " l-value of swizzle cannot have duplicate components", op); return true; } } - } + } return errorReturn; - default: + default: break; } error(line, " l-value required", op); @@ -317,6 +318,8 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIn case EvqConst: message = "can't modify a const"; break; case EvqConstReadOnly: message = "can't modify a const"; break; case EvqAttribute: message = "can't modify an attribute"; break; + case EvqFragmentIn: message = "can't modify an input"; break; + case EvqVertexIn: message = "can't modify an input"; break; case EvqUniform: message = "can't modify a uniform"; break; case EvqVaryingIn: message = "can't modify a varying"; break; case EvqFragCoord: message = "can't modify gl_FragCoord"; break; @@ -327,16 +330,11 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIn // // Type that can't be written to? // - switch (node->getBasicType()) { - case EbtSampler2D: - case EbtSamplerCube: - message = "can't modify a sampler"; - break; - case EbtVoid: + if (node->getBasicType() == EbtVoid) { message = "can't modify void"; - break; - default: - break; + } + if (IsSampler(node->getBasicType())) { + message = "can't modify a sampler"; } } @@ -396,7 +394,7 @@ bool TParseContext::constErrorCheck(TIntermTyped* node) // bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token) { - if (node->getBasicType() == EbtInt && node->getNominalSize() == 1) + if (node->isScalarInt()) return false; error(node->getLine(), "integer expression required", token); @@ -437,7 +435,7 @@ bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& id error(line, reservedErrMsg, "gl_"); return true; } - if (isWebGLBasedSpec(shaderSpec)) { + if (IsWebGLBasedSpec(shaderSpec)) { if (identifier.compare(0, 6, "webgl_") == 0) { error(line, reservedErrMsg, "webgl_"); return true; @@ -599,7 +597,7 @@ bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* t // bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType) { - if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) { + if (pType.type != EbtBool || pType.isAggregate()) { error(line, "boolean expression expected", ""); return true; } @@ -628,11 +626,20 @@ bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType) { - if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) && - pType.type == EbtStruct) { - error(line, "cannot be used with a structure", getQualifierString(pType.qualifier)); - - return true; + switch (pType.qualifier) + { + case EvqVaryingIn: + case EvqVaryingOut: + case EvqAttribute: + case EvqVertexIn: + case EvqFragmentOut: + if (pType.type == EbtStruct) + { + error(line, "cannot be used with a structure", getQualifierString(pType.qualifier)); + return true; + } + + default: break; } if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform")) @@ -641,6 +648,17 @@ bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPub return false; } +bool TParseContext::locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType) +{ + if (pType.layoutQualifier.location != -1) + { + error(line, "location must only be specified for a single input or output variable", "location"); + return true; + } + + return false; +} + bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type) { if ((qualifier == EvqOut || qualifier == EvqInOut) && @@ -657,7 +675,7 @@ bool TParseContext::containsSampler(TType& type) if (IsSampler(type.getBasicType())) return true; - if (type.getBasicType() == EbtStruct) { + if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) { const TFieldList& fields = type.getStruct()->fields(); for (unsigned int i = 0; i < fields.size(); ++i) { if (containsSampler(*fields[i]->type())) @@ -676,15 +694,49 @@ bool TParseContext::containsSampler(TType& type) bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size) { TIntermConstantUnion* constant = expr->getAsConstantUnion(); - if (constant == 0 || constant->getBasicType() != EbtInt) { + + if (constant == 0 || !constant->isScalarInt()) + { error(line, "array size must be a constant integer expression", ""); return true; } - size = constant->getIConst(0); + unsigned int unsignedSize = 0; + + if (constant->getBasicType() == EbtUInt) + { + unsignedSize = constant->getUConst(0); + size = static_cast(unsignedSize); + } + else + { + size = constant->getIConst(0); + + if (size < 0) + { + error(line, "array size must be non-negative", ""); + size = 1; + return true; + } + + unsignedSize = static_cast(size); + } + + if (size == 0) + { + error(line, "array size must be greater than zero", ""); + size = 1; + return true; + } + + // The size of arrays is restricted here to prevent issues further down the + // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to + // 4096 registers so this should be reasonable even for aggressively optimizable code. + const unsigned int sizeLimit = 65536; - if (size <= 0) { - error(line, "array size must be a positive integer", ""); + if (unsignedSize > sizeLimit) + { + error(line, "array size too large", ""); size = 1; return true; } @@ -699,7 +751,7 @@ bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* ex // bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type) { - if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConst)) { + if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) || (type.qualifier == EvqConst)) { error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str()); return true; } @@ -733,7 +785,7 @@ bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type // // Returns true if there was an error. // -bool TParseContext::arrayErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType type, TVariable*& variable) +bool TParseContext::arrayErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType &type, TVariable*& variable) { // // Don't check for reserved word use until after we know it's not in the symbol table, @@ -742,7 +794,7 @@ bool TParseContext::arrayErrorCheck(const TSourceLoc& line, TString& identifier, bool builtIn = false; bool sameScope = false; - TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope); + TSymbol* symbol = symbolTable.find(identifier, 0, &builtIn, &sameScope); if (symbol == 0 || !sameScope) { if (reservedErrorCheck(line, identifier)) return true; @@ -752,7 +804,7 @@ bool TParseContext::arrayErrorCheck(const TSourceLoc& line, TString& identifier, if (type.arraySize) variable->getType().setArraySize(type.arraySize); - if (! symbolTable.insert(*variable)) { + if (! symbolTable.declare(variable)) { delete variable; error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str()); return true; @@ -793,7 +845,7 @@ bool TParseContext::arrayErrorCheck(const TSourceLoc& line, TString& identifier, // // Returns true if there was an error. // -bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, bool array) +bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, const TString& identifier, TPublicType& type, bool array) { if (type.qualifier == EvqConst) { @@ -825,14 +877,14 @@ bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, TString& iden // // Returns true if there was an error. // -bool TParseContext::nonInitErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, TVariable*& variable) +bool TParseContext::nonInitErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& type, TVariable*& variable) { if (reservedErrorCheck(line, identifier)) recover(); variable = new TVariable(&identifier, TType(type)); - if (! symbolTable.insert(*variable)) { + if (! symbolTable.declare(variable)) { error(line, "redefinition", variable->getName().c_str()); delete variable; variable = 0; @@ -885,6 +937,45 @@ bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& e return false; } +bool TParseContext::singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier) +{ + if (structQualifierErrorCheck(identifierLocation, publicType)) + return true; + + // check for layout qualifier issues + const TLayoutQualifier layoutQualifier = publicType.layoutQualifier; + + if (layoutQualifier.matrixPacking != EmpUnspecified) + { + error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking), "only valid for interface blocks"); + return true; + } + + if (layoutQualifier.blockStorage != EbsUnspecified) + { + error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage), "only valid for interface blocks"); + return true; + } + + if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut && layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier)) + { + return true; + } + + return false; +} + +bool TParseContext::layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier) +{ + if (layoutQualifier.location != -1) + { + error(location, "invalid layout qualifier:", "location", "only valid on program inputs and outputs"); + return true; + } + + return false; +} + bool TParseContext::supportsExtension(const char* extension) { const TExtensionBehavior& extbehavior = extensionBehavior(); @@ -905,6 +996,22 @@ bool TParseContext::isExtensionEnabled(const char* extension) const return (iter->second == EBhEnable || iter->second == EBhRequire); } +void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior) +{ + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + directiveHandler.handleExtension(srcLoc, extName, behavior); +} + +void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value) +{ + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + directiveHandler.handlePragma(srcLoc, name, value); +} + ///////////////////////////////////////////////////////////////////////////////// // // Non-Errors. @@ -916,14 +1023,14 @@ bool TParseContext::isExtensionEnabled(const char* extension) const // // Return the function symbol if found, otherwise 0. // -const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, bool *builtIn) +const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int shaderVersion, bool *builtIn) { // First find by unmangled name to check whether the function name has been // hidden by a variable name or struct typename. // If a function is found, check for one with a matching argument list. - const TSymbol* symbol = symbolTable.find(call->getName(), builtIn); + const TSymbol* symbol = symbolTable.find(call->getName(), shaderVersion, builtIn); if (symbol == 0 || symbol->isFunction()) { - symbol = symbolTable.find(call->getMangledName(), builtIn); + symbol = symbolTable.find(call->getMangledName(), shaderVersion, builtIn); } if (symbol == 0) { @@ -943,7 +1050,7 @@ const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* // Initializers show up in several places in the grammar. Have one set of // code to handle them here. // -bool TParseContext::executeInitializer(const TSourceLoc& line, TString& identifier, TPublicType& pType, +bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType, TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable) { TType type = TType(pType); @@ -959,7 +1066,7 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, TString& identifi // add variable to symbol table // variable = new TVariable(&identifier, type); - if (! symbolTable.insert(*variable)) { + if (! symbolTable.declare(variable)) { error(line, "redefinition", variable->getName().c_str()); return true; // don't delete variable, it's used by error recovery, and the pool @@ -997,7 +1104,7 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, TString& identifi if (initializer->getAsConstantUnion()) { variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); } else if (initializer->getAsSymbolNode()) { - const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol()); + const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0); const TVariable* tVar = static_cast(symbol); ConstantUnion* constArray = tVar->getConstPointer(); @@ -1035,8 +1142,8 @@ bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode) // check if all the child nodes are constants so that they can be inserted into // the parent node - TIntermSequence &sequence = aggrNode->getSequence() ; - for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) { + TIntermSequence *sequence = aggrNode->getSequence() ; + for (TIntermSequence::iterator p = sequence->begin(); p != sequence->end(); ++p) { if (!(*p)->getAsTyped()->getAsConstantUnion()) return false; } @@ -1044,269 +1151,514 @@ bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode) return allConstant; } -// This function is used to test for the correctness of the parameters passed to various constructor functions -// and also convert them to the right datatype if it is allowed and required. -// -// Returns 0 for an error or the constructed node (aggregate or typed) for no error. -// -TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, const TSourceLoc& line) +TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier) { - if (node == 0) - return 0; + TPublicType returnType = typeSpecifier; + returnType.qualifier = qualifier; + returnType.layoutQualifier = layoutQualifier; - TIntermAggregate* aggrNode = node->getAsAggregate(); - - TFieldList::const_iterator memberFields; - if (op == EOpConstructStruct) - memberFields = type->getStruct()->fields().begin(); - - TType elementType = *type; - if (type->isArray()) - elementType.clearArrayness(); - - bool singleArg; - if (aggrNode) { - if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1) - singleArg = true; - else - singleArg = false; - } else - singleArg = true; - - TIntermTyped *newNode; - if (singleArg) { - // If structure constructor or array constructor is being called - // for only one parameter inside the structure, we need to call constructStruct function once. - if (type->isArray()) - newNode = constructStruct(node, &elementType, 1, node->getLine(), false); - else if (op == EOpConstructStruct) - newNode = constructStruct(node, (*memberFields)->type(), 1, node->getLine(), false); - else - newNode = constructBuiltIn(type, op, node, node->getLine(), false); + if (typeSpecifier.array) + { + error(typeSpecifier.line, "not supported", "first-class array"); + recover(); + returnType.setArray(false); + } - if (newNode && newNode->getAsAggregate()) { - TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type); - if (constConstructor) - return constConstructor; + if (shaderVersion < 300) + { + if (qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) + { + error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier)); + recover(); } - return newNode; - } - - // - // Handle list of arguments. - // - TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor - // if the structure constructor contains more than one parameter, then construct - // each parameter - - int paramCount = 0; // keeps a track of the constructor parameter number being checked - - // for each parameter to the constructor call, check to see if the right type is passed or convert them - // to the right type if possible (and allowed). - // for structure constructors, just check if the right type is passed, no conversion is allowed. - - for (TIntermSequence::iterator p = sequenceVector.begin(); - p != sequenceVector.end(); p++, paramCount++) { - if (type->isArray()) - newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true); - else if (op == EOpConstructStruct) - newNode = constructStruct(*p, memberFields[paramCount]->type(), paramCount+1, node->getLine(), true); - else - newNode = constructBuiltIn(type, op, *p, node->getLine(), true); - - if (newNode) { - *p = newNode; + if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) && + (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) + { + error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier)); + recover(); } } + else + { + switch (qualifier) + { + case EvqSmoothIn: + case EvqSmoothOut: + case EvqVertexOut: + case EvqFragmentIn: + case EvqCentroidOut: + case EvqCentroidIn: + if (typeSpecifier.type == EbtBool) + { + error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier)); + recover(); + } + if (typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt) + { + error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier)); + recover(); + } + break; - TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line); - TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type); - if (constConstructor) - return constConstructor; + case EvqVertexIn: + case EvqFragmentOut: + case EvqFlatIn: + case EvqFlatOut: + if (typeSpecifier.type == EbtBool) + { + error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier)); + recover(); + } + break; - return constructor; + default: break; + } + } + + return returnType; } -TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type) +TIntermAggregate* TParseContext::parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier) { - bool canBeFolded = areAllChildConst(aggrNode); - aggrNode->setType(type); - if (canBeFolded) { - bool returnVal = false; - ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()]; - if (aggrNode->getSequence().size() == 1) { - returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true); - } - else { - returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type); - } - if (returnVal) - return 0; + TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation); + TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation); - return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine()); + if (identifier != "") + { + if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier)) + recover(); + + // this error check can mutate the type + if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false)) + recover(); + + TVariable* variable = 0; + + if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable)) + recover(); + + if (variable && symbol) + { + symbol->setId(variable->getUniqueId()); + } } - return 0; + return aggregate; } -// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value -// for the parameter to the constructor (passed to this function). Essentially, it converts -// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a -// float, then float is converted to int. -// -// Returns 0 for an error or the constructed node. -// -TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, const TSourceLoc& line, bool subset) +TIntermAggregate* TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression) { - TIntermTyped* newNode; - TOperator basicOp; + if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier)) + recover(); - // - // First, convert types as needed. - // - switch (op) { - case EOpConstructVec2: - case EOpConstructVec3: - case EOpConstructVec4: - case EOpConstructMat2: - case EOpConstructMat3: - case EOpConstructMat4: - case EOpConstructFloat: - basicOp = EOpConstructFloat; - break; + // this error check can mutate the type + if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true)) + recover(); - case EOpConstructIVec2: - case EOpConstructIVec3: - case EOpConstructIVec4: - case EOpConstructInt: - basicOp = EOpConstructInt; - break; + if (arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType)) + { + recover(); + } - case EOpConstructBVec2: - case EOpConstructBVec3: - case EOpConstructBVec4: - case EOpConstructBool: - basicOp = EOpConstructBool; - break; + TPublicType arrayType = publicType; - default: - error(line, "unsupported construction", ""); + int size; + if (arraySizeErrorCheck(identifierLocation, indexExpression, size)) + { recover(); - - return 0; } - newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable); - if (newNode == 0) { - error(line, "can't convert", "constructor"); - return 0; + else + { + arrayType.setArray(true, size); } - // - // Now, if there still isn't an operation to do the construction, and we need one, add one. - // - - // Otherwise, skip out early. - if (subset || (newNode != node && newNode->getType() == *type)) - return newNode; + TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(arrayType), identifierLocation); + TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation); + TVariable* variable = 0; + + if (arrayErrorCheck(identifierLocation, identifier, arrayType, variable)) + recover(); + + if (variable && symbol) + { + symbol->setId(variable->getUniqueId()); + } - // setAggregateOperator will insert a new node for the constructor, as needed. - return intermediate.setAggregateOperator(newNode, op, line); + return aggregate; } -// This function tests for the type of the parameters to the structures constructors. Raises -// an error message if the expected type does not match the parameter passed to the constructor. -// -// Returns 0 for an error or the input node itself if the expected and the given parameter types match. -// -TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, const TSourceLoc& line, bool subset) +TIntermAggregate* TParseContext::parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer) { - if (*type == node->getAsTyped()->getType()) { - if (subset) - return node->getAsTyped(); - else - return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line); - } else { - std::stringstream extraInfoStream; - extraInfoStream << "cannot convert parameter " << paramCount - << " from '" << node->getAsTyped()->getType().getBasicString() - << "' to '" << type->getBasicString() << "'"; - std::string extraInfo = extraInfoStream.str(); - error(line, "", "constructor", extraInfo.c_str()); + if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier)) recover(); - } - return 0; + TIntermNode* intermNode; + if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode)) + { + // + // Build intermediate representation + // + return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : NULL; + } + else + { + recover(); + return NULL; + } } -// -// This function returns the tree representation for the vector field(s) being accessed from contant vector. -// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is -// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol -// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of -// a constant matrix. -// -TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line) +TIntermAggregate* TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier) { - TIntermTyped* typedNode; - TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + if (publicType.type == EbtInvariant && !identifierSymbol) + { + error(identifierLocation, "undeclared identifier declared as invariant", identifier.c_str()); + recover(); + } - ConstantUnion *unionArray; - if (tempConstantNode) { - unionArray = tempConstantNode->getUnionArrayPointer(); + TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation); + TIntermAggregate* intermAggregate = intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation); - if (!unionArray) { - return node; - } - } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error - error(line, "Cannot offset into the vector", "Error"); + if (structQualifierErrorCheck(identifierLocation, publicType)) recover(); - return 0; - } + if (locationDeclaratorListCheck(identifierLocation, publicType)) + recover(); - ConstantUnion* constArray = new ConstantUnion[fields.num]; + if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false)) + recover(); - for (int i = 0; i < fields.num; i++) { - if (fields.offsets[i] >= node->getType().getNominalSize()) { - std::stringstream extraInfoStream; - extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'"; - std::string extraInfo = extraInfoStream.str(); - error(line, "", "[", extraInfo.c_str()); - recover(); - fields.offsets[i] = 0; - } - - constArray[i] = unionArray[fields.offsets[i]]; + TVariable* variable = 0; + if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable)) + recover(); + if (symbol && variable) + symbol->setId(variable->getUniqueId()); - } - typedNode = intermediate.addConstantUnion(constArray, node->getType(), line); - return typedNode; + return intermAggregate; } -// -// This function returns the column being accessed from a constant matrix. The values are retrieved from -// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input -// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a -// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure) -// -TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line) +TIntermAggregate* TParseContext::parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression) { - TIntermTyped* typedNode; - TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + if (structQualifierErrorCheck(identifierLocation, publicType)) + recover(); - if (index >= node->getType().getNominalSize()) { - std::stringstream extraInfoStream; - extraInfoStream << "matrix field selection out of range '" << index << "'"; - std::string extraInfo = extraInfoStream.str(); - error(line, "", "[", extraInfo.c_str()); + if (locationDeclaratorListCheck(identifierLocation, publicType)) recover(); - index = 0; + + if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true)) + recover(); + + if (arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType)) + { + recover(); + } + else if (indexExpression) + { + int size; + if (arraySizeErrorCheck(arrayLocation, indexExpression, size)) + recover(); + TPublicType arrayType(publicType); + arrayType.setArray(true, size); + TVariable* variable = NULL; + if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable)) + recover(); + TType type = TType(arrayType); + type.setArraySize(size); + + return intermediate.growAggregate(declaratorList, intermediate.addSymbol(variable ? variable->getUniqueId() : 0, identifier, type, identifierLocation), identifierLocation); + } + else + { + TPublicType arrayType(publicType); + arrayType.setArray(true); + TVariable* variable = NULL; + if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable)) + recover(); + } + + return NULL; +} + +TIntermAggregate* TParseContext::parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer) +{ + if (structQualifierErrorCheck(identifierLocation, publicType)) + recover(); + + if (locationDeclaratorListCheck(identifierLocation, publicType)) + recover(); + + TIntermNode* intermNode; + if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode)) + { + // + // build the intermediate representation + // + if (intermNode) + { + return intermediate.growAggregate(declaratorList, intermNode, initLocation); + } + else + { + return declaratorList; + } + } + else + { + recover(); + return NULL; + } +} + +void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier) +{ + if (typeQualifier.qualifier != EvqUniform) + { + error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "global layout must be uniform"); + recover(); + return; + } + + const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier; + ASSERT(!layoutQualifier.isEmpty()); + + if (shaderVersion < 300) + { + error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout"); + recover(); + return; + } + + if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier)) + { + recover(); + return; + } + + if (layoutQualifier.matrixPacking != EmpUnspecified) + { + defaultMatrixPacking = layoutQualifier.matrixPacking; + } + + if (layoutQualifier.blockStorage != EbsUnspecified) + { + defaultBlockStorage = layoutQualifier.blockStorage; + } +} + +TFunction *TParseContext::addConstructorFunc(TPublicType publicType) +{ + TOperator op = EOpNull; + if (publicType.userDef) + { + op = EOpConstructStruct; + } + else + { + switch (publicType.type) + { + case EbtFloat: + if (publicType.isMatrix()) + { + // TODO: non-square matrices + switch(publicType.getCols()) + { + case 2: op = EOpConstructMat2; break; + case 3: op = EOpConstructMat3; break; + case 4: op = EOpConstructMat4; break; + } + } + else + { + switch(publicType.getNominalSize()) + { + case 1: op = EOpConstructFloat; break; + case 2: op = EOpConstructVec2; break; + case 3: op = EOpConstructVec3; break; + case 4: op = EOpConstructVec4; break; + } + } + break; + + case EbtInt: + switch(publicType.getNominalSize()) + { + case 1: op = EOpConstructInt; break; + case 2: op = EOpConstructIVec2; break; + case 3: op = EOpConstructIVec3; break; + case 4: op = EOpConstructIVec4; break; + } + break; + + case EbtUInt: + switch(publicType.getNominalSize()) + { + case 1: op = EOpConstructUInt; break; + case 2: op = EOpConstructUVec2; break; + case 3: op = EOpConstructUVec3; break; + case 4: op = EOpConstructUVec4; break; + } + break; + + case EbtBool: + switch(publicType.getNominalSize()) + { + case 1: op = EOpConstructBool; break; + case 2: op = EOpConstructBVec2; break; + case 3: op = EOpConstructBVec3; break; + case 4: op = EOpConstructBVec4; break; + } + break; + + default: break; + } + + if (op == EOpNull) + { + error(publicType.line, "cannot construct this type", getBasicString(publicType.type)); + recover(); + publicType.type = EbtFloat; + op = EOpConstructFloat; + } + } + + TString tempString; + TType type(publicType); + return new TFunction(&tempString, type, op); +} + +// This function is used to test for the correctness of the parameters passed to various constructor functions +// and also convert them to the right datatype if it is allowed and required. +// +// Returns 0 for an error or the constructed node (aggregate or typed) for no error. +// +TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, const TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line) +{ + TIntermAggregate *aggregateArguments = arguments->getAsAggregate(); + + if (!aggregateArguments) + { + aggregateArguments = new TIntermAggregate; + aggregateArguments->getSequence()->push_back(arguments); + } + + if (op == EOpConstructStruct) + { + const TFieldList &fields = type->getStruct()->fields(); + TIntermSequence *args = aggregateArguments->getSequence(); + + for (size_t i = 0; i < fields.size(); i++) + { + if ((*args)[i]->getAsTyped()->getType() != *fields[i]->type()) + { + error(line, "Structure constructor arguments do not match structure fields", "Error"); + recover(); + + return 0; + } + } + } + + // Turn the argument list itself into a constructor + TIntermTyped *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line); + TIntermTyped *constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type); + if (constConstructor) + { + return constConstructor; + } + + return constructor; +} + +TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type) +{ + bool canBeFolded = areAllChildConst(aggrNode); + aggrNode->setType(type); + if (canBeFolded) { + bool returnVal = false; + ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()]; + if (aggrNode->getSequence()->size() == 1) { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type, true); + } + else { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type); + } + if (returnVal) + return 0; + + return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine()); + } + + return 0; +} + +// +// This function returns the tree representation for the vector field(s) being accessed from contant vector. +// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is +// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol +// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of +// a constant matrix. +// +TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + ConstantUnion *unionArray; + if (tempConstantNode) { + unionArray = tempConstantNode->getUnionArrayPointer(); + + if (!unionArray) { + return node; + } + } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error + error(line, "Cannot offset into the vector", "Error"); + recover(); + + return 0; + } + + ConstantUnion* constArray = new ConstantUnion[fields.num]; + + for (int i = 0; i < fields.num; i++) { + if (fields.offsets[i] >= node->getType().getNominalSize()) { + std::stringstream extraInfoStream; + extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + fields.offsets[i] = 0; + } + + constArray[i] = unionArray[fields.offsets[i]]; + + } + typedNode = intermediate.addConstantUnion(constArray, node->getType(), line); + return typedNode; +} + +// +// This function returns the column being accessed from a constant matrix. The values are retrieved from +// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input +// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a +// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure) +// +TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + if (index >= node->getType().getCols()) { + std::stringstream extraInfoStream; + extraInfoStream << "matrix field selection out of range '" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + index = 0; } if (tempConstantNode) { ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); - int size = tempConstantNode->getType().getNominalSize(); + int size = tempConstantNode->getType().getCols(); typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line); } else { error(line, "Cannot offset into the matrix", "Error"); @@ -1342,9 +1694,9 @@ TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, co } if (tempConstantNode) { - size_t arrayElementSize = arrayElementType.getObjectSize(); - ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); - typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); + size_t arrayElementSize = arrayElementType.getObjectSize(); + ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); + typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); } else { error(line, "Cannot offset into the array", "Error"); recover(); @@ -1361,11 +1713,11 @@ TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, co // If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr // function and returns the parse-tree with the values of the embedded/nested struct. // -TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, const TSourceLoc& line) +TIntermTyped* TParseContext::addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line) { const TFieldList& fields = node->getType().getStruct()->fields(); - size_t instanceSize = 0; + for (size_t index = 0; index < fields.size(); ++index) { if (fields[index]->name() == identifier) { break; @@ -1374,8 +1726,8 @@ TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* n } } - TIntermTyped* typedNode = 0; - TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + TIntermTyped *typedNode; + TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion(); if (tempConstantNode) { ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer(); @@ -1390,6 +1742,146 @@ TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* n return typedNode; } +// +// Interface/uniform blocks +// +TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList, + const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine) +{ + if (reservedErrorCheck(nameLine, blockName)) + recover(); + + if (typeQualifier.qualifier != EvqUniform) + { + error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform"); + recover(); + } + + TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; + if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier)) + { + recover(); + } + + if (blockLayoutQualifier.matrixPacking == EmpUnspecified) + { + blockLayoutQualifier.matrixPacking = defaultMatrixPacking; + } + + if (blockLayoutQualifier.blockStorage == EbsUnspecified) + { + blockLayoutQualifier.blockStorage = defaultBlockStorage; + } + + TSymbol* blockNameSymbol = new TInterfaceBlockName(&blockName); + if (!symbolTable.declare(blockNameSymbol)) { + error(nameLine, "redefinition", blockName.c_str(), "interface block name"); + recover(); + } + + // check for sampler types and apply layout qualifiers + for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) { + TField* field = (*fieldList)[memberIndex]; + TType* fieldType = field->type(); + if (IsSampler(fieldType->getBasicType())) { + error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks"); + recover(); + } + + const TQualifier qualifier = fieldType->getQualifier(); + switch (qualifier) + { + case EvqGlobal: + case EvqUniform: + break; + default: + error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier)); + recover(); + break; + } + + // check layout qualifiers + TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); + if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier)) + { + recover(); + } + + if (fieldLayoutQualifier.blockStorage != EbsUnspecified) + { + error(field->line(), "invalid layout qualifier:", getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here"); + recover(); + } + + if (fieldLayoutQualifier.matrixPacking == EmpUnspecified) + { + fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking; + } + else if (!fieldType->isMatrix()) + { + error(field->line(), "invalid layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "can only be used on matrix types"); + recover(); + } + + fieldType->setLayoutQualifier(fieldLayoutQualifier); + } + + // add array index + int arraySize = 0; + if (arrayIndex != NULL) + { + if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize)) + recover(); + } + + TInterfaceBlock* interfaceBlock = new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier); + TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, arraySize); + + TString symbolName = ""; + int symbolId = 0; + + if (!instanceName) + { + // define symbols for the members of the interface block + for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) + { + TField* field = (*fieldList)[memberIndex]; + TType* fieldType = field->type(); + + // set parent pointer of the field variable + fieldType->setInterfaceBlock(interfaceBlock); + + TVariable* fieldVariable = new TVariable(&field->name(), *fieldType); + fieldVariable->setQualifier(typeQualifier.qualifier); + + if (!symbolTable.declare(fieldVariable)) { + error(field->line(), "redefinition", field->name().c_str(), "interface block member name"); + recover(); + } + } + } + else + { + // add a symbol for this interface block + TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false); + instanceTypeDef->setQualifier(typeQualifier.qualifier); + + if (!symbolTable.declare(instanceTypeDef)) { + error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name"); + recover(); + } + + symbolId = instanceTypeDef->getUniqueId(); + symbolName = instanceTypeDef->getName(); + } + + TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine); + aggregate->setOp(EOpDeclaration); + + exitStructDeclaration(); + return aggregate; +} + bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier) { ++structNestingLevel; @@ -1418,7 +1910,7 @@ const int kWebGLMaxStructNesting = 4; bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field) { - if (!isWebGLBasedSpec(shaderSpec)) { + if (!IsWebGLBasedSpec(shaderSpec)) { return false; } @@ -1531,6 +2023,17 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co } else { + if (baseExpression->isInterfaceBlock()) + { + error(location, "", "[", "array indexes for interface blocks arrays must be constant integral expressions"); + recover(); + } + else if (baseExpression->getQualifier() == EvqFragmentOut) + { + error(location, "", "[", "array indexes for fragment outputs must be constant integral expressions"); + recover(); + } + indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location); } @@ -1548,9 +2051,14 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co TType copyOfType(baseType.getStruct()); indexedExpression->setType(copyOfType); } + else if (baseType.isInterfaceBlock()) + { + TType copyOfType(baseType.getInterfaceBlock(), baseType.getQualifier(), baseType.getLayoutQualifier(), 0); + indexedExpression->setType(copyOfType); + } else { - indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, baseExpression->getNominalSize(), baseExpression->isMatrix())); + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, baseExpression->getNominalSize(), baseExpression->getSecondarySize())); } if (baseExpression->getType().getQualifier() == EvqConst) @@ -1561,7 +2069,7 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co else if (baseExpression->isMatrix()) { TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary; - indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, baseExpression->getNominalSize())); + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, baseExpression->getRows())); } else if (baseExpression->isVector()) { @@ -1576,6 +2084,408 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co return indexedExpression; } +TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation) +{ + TIntermTyped *indexedExpression = NULL; + + if (baseExpression->isArray()) + { + error(fieldLocation, "cannot apply dot operator to an array", "."); + recover(); + } + + if (baseExpression->isVector()) + { + TVectorFields fields; + if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields, fieldLocation)) + { + fields.num = 1; + fields.offsets[0] = 0; + recover(); + } + + if (baseExpression->getType().getQualifier() == EvqConst) + { + // constant folding for vector fields + indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation); + if (indexedExpression == 0) + { + recover(); + indexedExpression = baseExpression; + } + else + { + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqConst, (int) (fieldString).size())); + } + } + else + { + TString vectorString = fieldString; + TIntermTyped* index = intermediate.addSwizzle(fields, fieldLocation); + indexedExpression = intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation); + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, (int) vectorString.size())); + } + } + else if (baseExpression->isMatrix()) + { + TMatrixFields fields; + if (!parseMatrixFields(fieldString, baseExpression->getCols(), baseExpression->getRows(), fields, fieldLocation)) + { + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = 0; + fields.col = 0; + recover(); + } + + if (fields.wholeRow || fields.wholeCol) + { + error(dotLocation, " non-scalar fields not implemented yet", "."); + recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(0); + TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation); + indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation); + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(),EvqTemporary, baseExpression->getCols(), baseExpression->getRows())); + } + else + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(fields.col * baseExpression->getRows() + fields.row); + TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation); + indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation); + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision())); + } + } + else if (baseExpression->getBasicType() == EbtStruct) + { + bool fieldFound = false; + const TFieldList& fields = baseExpression->getType().getStruct()->fields(); + if (fields.empty()) + { + error(dotLocation, "structure has no fields", "Internal Error"); + recover(); + indexedExpression = baseExpression; + } + else + { + unsigned int i; + for (i = 0; i < fields.size(); ++i) + { + if (fields[i]->name() == fieldString) + { + fieldFound = true; + break; + } + } + if (fieldFound) + { + if (baseExpression->getType().getQualifier() == EvqConst) + { + indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation); + if (indexedExpression == 0) + { + recover(); + indexedExpression = baseExpression; + } + else + { + indexedExpression->setType(*fields[i]->type()); + // change the qualifier of the return type, not of the structure field + // as the structure definition is shared between various structures. + indexedExpression->getTypePointer()->setQualifier(EvqConst); + } + } + else + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(i); + TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation); + indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation); + indexedExpression->setType(*fields[i]->type()); + } + } + else + { + error(dotLocation, " no such field in structure", fieldString.c_str()); + recover(); + indexedExpression = baseExpression; + } + } + } + else if (baseExpression->isInterfaceBlock()) + { + bool fieldFound = false; + const TFieldList& fields = baseExpression->getType().getInterfaceBlock()->fields(); + if (fields.empty()) + { + error(dotLocation, "interface block has no fields", "Internal Error"); + recover(); + indexedExpression = baseExpression; + } + else + { + unsigned int i; + for (i = 0; i < fields.size(); ++i) + { + if (fields[i]->name() == fieldString) + { + fieldFound = true; + break; + } + } + if (fieldFound) + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(i); + TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation); + indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, dotLocation); + indexedExpression->setType(*fields[i]->type()); + } + else + { + error(dotLocation, " no such field in interface block", fieldString.c_str()); + recover(); + indexedExpression = baseExpression; + } + } + } + else + { + if (shaderVersion < 300) + { + error(dotLocation, " field selection requires structure, vector, or matrix on left hand side", fieldString.c_str()); + } + else + { + error(dotLocation, " field selection requires structure, vector, matrix, or interface block on left hand side", fieldString.c_str()); + } + recover(); + indexedExpression = baseExpression; + } + + return indexedExpression; +} + +TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine) +{ + TLayoutQualifier qualifier; + + qualifier.location = -1; + qualifier.matrixPacking = EmpUnspecified; + qualifier.blockStorage = EbsUnspecified; + + if (qualifierType == "shared") + { + qualifier.blockStorage = EbsShared; + } + else if (qualifierType == "packed") + { + qualifier.blockStorage = EbsPacked; + } + else if (qualifierType == "std140") + { + qualifier.blockStorage = EbsStd140; + } + else if (qualifierType == "row_major") + { + qualifier.matrixPacking = EmpRowMajor; + } + else if (qualifierType == "column_major") + { + qualifier.matrixPacking = EmpColumnMajor; + } + else if (qualifierType == "location") + { + error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "location requires an argument"); + recover(); + } + else + { + error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str()); + recover(); + } + + return qualifier; +} + +TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine) +{ + TLayoutQualifier qualifier; + + qualifier.location = -1; + qualifier.matrixPacking = EmpUnspecified; + qualifier.blockStorage = EbsUnspecified; + + if (qualifierType != "location") + { + error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "only location may have arguments"); + recover(); + } + else + { + // must check that location is non-negative + if (intValue < 0) + { + error(intValueLine, "out of range:", intValueString.c_str(), "location must be non-negative"); + recover(); + } + else + { + qualifier.location = intValue; + } + } + + return qualifier; +} + +TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier) +{ + TLayoutQualifier joinedQualifier = leftQualifier; + + if (rightQualifier.location != -1) + { + joinedQualifier.location = rightQualifier.location; + } + if (rightQualifier.matrixPacking != EmpUnspecified) + { + joinedQualifier.matrixPacking = rightQualifier.matrixPacking; + } + if (rightQualifier.blockStorage != EbsUnspecified) + { + joinedQualifier.blockStorage = rightQualifier.blockStorage; + } + + return joinedQualifier; +} + +TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier, + const TSourceLoc &storageLoc, TQualifier storageQualifier) +{ + TQualifier mergedQualifier = EvqSmoothIn; + + if (storageQualifier == EvqFragmentIn) { + if (interpolationQualifier == EvqSmooth) + mergedQualifier = EvqSmoothIn; + else if (interpolationQualifier == EvqFlat) + mergedQualifier = EvqFlatIn; + else UNREACHABLE(); + } + else if (storageQualifier == EvqCentroidIn) { + if (interpolationQualifier == EvqSmooth) + mergedQualifier = EvqCentroidIn; + else if (interpolationQualifier == EvqFlat) + mergedQualifier = EvqFlatIn; + else UNREACHABLE(); + } + else if (storageQualifier == EvqVertexOut) { + if (interpolationQualifier == EvqSmooth) + mergedQualifier = EvqSmoothOut; + else if (interpolationQualifier == EvqFlat) + mergedQualifier = EvqFlatOut; + else UNREACHABLE(); + } + else if (storageQualifier == EvqCentroidOut) { + if (interpolationQualifier == EvqSmooth) + mergedQualifier = EvqCentroidOut; + else if (interpolationQualifier == EvqFlat) + mergedQualifier = EvqFlatOut; + else UNREACHABLE(); + } + else { + error(interpolationLoc, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString(interpolationQualifier)); + recover(); + + mergedQualifier = storageQualifier; + } + + TPublicType type; + type.setBasic(EbtVoid, mergedQualifier, storageLoc); + return type; +} + +TFieldList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList) +{ + if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier)) { + recover(); + } + + for (unsigned int i = 0; i < fieldList->size(); ++i) { + // + // Careful not to replace already known aspects of type, like array-ness + // + TType* type = (*fieldList)[i]->type(); + type->setBasicType(typeSpecifier.type); + type->setPrimarySize(typeSpecifier.primarySize); + type->setSecondarySize(typeSpecifier.secondarySize); + type->setPrecision(typeSpecifier.precision); + type->setQualifier(typeSpecifier.qualifier); + type->setLayoutQualifier(typeSpecifier.layoutQualifier); + + // don't allow arrays of arrays + if (type->isArray()) { + if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier)) + recover(); + } + if (typeSpecifier.array) + type->setArraySize(typeSpecifier.arraySize); + if (typeSpecifier.userDef) { + type->setStruct(typeSpecifier.userDef->getStruct()); + } + + if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i])) { + recover(); + } + } + + return fieldList; +} + +TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList) +{ + TStructure* structure = new TStructure(structName, fieldList); + TType* structureType = new TType(structure); + + structure->setUniqueId(TSymbolTable::nextUniqueId()); + + if (!structName->empty()) + { + if (reservedErrorCheck(nameLine, *structName)) + { + recover(); + } + TVariable* userTypeDef = new TVariable(structName, *structureType, true); + if (!symbolTable.declare(userTypeDef)) { + error(nameLine, "redefinition", structName->c_str(), "struct"); + recover(); + } + } + + // ensure we do not specify any storage qualifiers on the struct members + for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++) + { + const TField &field = *(*fieldList)[typeListIndex]; + const TQualifier qualifier = field.type()->getQualifier(); + switch (qualifier) + { + case EvqGlobal: + case EvqTemporary: + break; + default: + error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier)); + recover(); + break; + } + } + + TPublicType publicType; + publicType.setBasic(EbtStruct, EvqTemporary, structLine); + publicType.userDef = structureType; + exitStructDeclaration(); + + return publicType; +} + // // Parse an array of strings using yyparse. // diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.h b/src/3rdparty/angle/src/compiler/translator/ParseContext.h index b324e575d3..a402eec78e 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.h +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.h @@ -1,17 +1,17 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // #ifndef _PARSER_HELPER_INCLUDED_ #define _PARSER_HELPER_INCLUDED_ +#include "compiler/translator/Compiler.h" #include "compiler/translator/Diagnostics.h" #include "compiler/translator/DirectiveHandler.h" #include "compiler/translator/localintermediate.h" -#include "compiler/preprocessor/Preprocessor.h" -#include "compiler/translator/ShHandle.h" #include "compiler/translator/SymbolTable.h" +#include "compiler/preprocessor/Preprocessor.h" struct TMatrixFields { bool wholeRow; @@ -25,7 +25,7 @@ struct TMatrixFields { // they can be passed to the parser without needing a global. // struct TParseContext { - TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) : + TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, sh::GLenum type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) : intermediate(interm), symbolTable(symt), shaderType(type), @@ -38,14 +38,18 @@ struct TParseContext { currentFunctionType(NULL), functionReturnsValue(false), checksPrecisionErrors(checksPrecErrors), + defaultMatrixPacking(EmpColumnMajor), + defaultBlockStorage(EbsShared), diagnostics(is), - directiveHandler(ext, diagnostics), + shaderVersion(100), + directiveHandler(ext, diagnostics, shaderVersion), preprocessor(&diagnostics, &directiveHandler), scanner(NULL) { } TIntermediate& intermediate; // to hold and build a parse tree TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed - ShShaderType shaderType; // vertex or fragment language (future: pack or unpack) + sh::GLenum shaderType; // vertex or fragment language (future: pack or unpack) ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL. + int shaderVersion; int compileOptions; const char* sourcePath; // Path of source file or NULL. TIntermNode* treeRoot; // root of parse tree being created @@ -55,12 +59,15 @@ struct TParseContext { bool functionReturnsValue; // true if a non-void function has a return bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit. bool fragmentPrecisionHigh; // true if highp precision is supported in the fragment language. + TLayoutMatrixPacking defaultMatrixPacking; + TLayoutBlockStorage defaultBlockStorage; TString HashErrMsg; TDiagnostics diagnostics; TDirectiveHandler directiveHandler; pp::Preprocessor preprocessor; void* scanner; + int getShaderVersion() const { return shaderVersion; } int numErrors() const { return diagnostics.numErrors(); } TInfoSink& infoSink() { return diagnostics.infoSink(); } void error(const TSourceLoc& loc, const char *reason, const char* token, @@ -71,7 +78,7 @@ struct TParseContext { void recover(); bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc& line); - bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, const TSourceLoc& line); + bool parseMatrixFields(const TString&, int matCols, int matRows, TMatrixFields&, const TSourceLoc& line); bool reservedErrorCheck(const TSourceLoc& line, const TString& identifier); void assignError(const TSourceLoc& line, const char* op, TString left, TString right); @@ -86,38 +93,64 @@ struct TParseContext { bool arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size); bool arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type); bool arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type); - bool arrayErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType type, TVariable*& variable); + bool arrayErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType &type, TVariable*& variable); bool voidErrorCheck(const TSourceLoc&, const TString&, const TPublicType&); bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*); bool boolErrorCheck(const TSourceLoc&, const TPublicType&); bool samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason); bool structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType); + bool locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType); bool parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type); - bool nonInitConstErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, bool array); - bool nonInitErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, TVariable*& variable); + bool nonInitConstErrorCheck(const TSourceLoc& line, const TString& identifier, TPublicType& type, bool array); + bool nonInitErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& type, TVariable*& variable); bool paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type); bool extensionErrorCheck(const TSourceLoc& line, const TString&); + bool singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier); + bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier); const TPragma& pragma() const { return directiveHandler.pragma(); } const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); } bool supportsExtension(const char* extension); bool isExtensionEnabled(const char* extension) const; + void handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior); + void handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value); bool containsSampler(TType& type); bool areAllChildConst(TIntermAggregate* aggrNode); - const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, bool *builtIn = 0); - bool executeInitializer(const TSourceLoc& line, TString& identifier, TPublicType& pType, + const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, int shaderVersion, bool *builtIn = 0); + bool executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType, TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0); + TPublicType addFullySpecifiedType(TQualifier qualifier, const TPublicType& typeSpecifier); + TPublicType addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier); + TIntermAggregate* parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier); + TIntermAggregate* parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression); + TIntermAggregate* parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer); + TIntermAggregate* parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier); + TIntermAggregate* parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression); + TIntermAggregate* parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer); + void parseGlobalLayoutQualifier(const TPublicType &typeQualifier); + TFunction *addConstructorFunc(TPublicType publicType); TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&); TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type); - TIntermTyped* constructStruct(TIntermNode*, TType*, int, const TSourceLoc&, bool subset); - TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, const TSourceLoc&, bool subset); TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&); TIntermTyped* addConstMatrixNode(int , TIntermTyped*, const TSourceLoc&); TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line); - TIntermTyped* addConstStruct(TString& , TIntermTyped*, const TSourceLoc&); + TIntermTyped* addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line); TIntermTyped* addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression); + TIntermTyped* addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation); + + TFieldList *addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList); + TPublicType addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList); + + TIntermAggregate* addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList, + const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine); + + TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine); + TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine); + TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier); + TPublicType joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier, + const TSourceLoc &storageLoc, TQualifier storageQualifier); // Performs an error check for embedded struct declarations. // Returns true if an error was raised due to the declaration of diff --git a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.cpp b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.cpp index abe70262f2..887cb66504 100644 --- a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.cpp +++ b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.cpp @@ -6,43 +6,44 @@ #include "compiler/translator/PoolAlloc.h" -#ifndef _MSC_VER -#include -#endif -#include +#include "compiler/translator/InitializeGlobals.h" +#include "common/platform.h" #include "common/angleutils.h" -#include "compiler/translator/InitializeGlobals.h" -#include "compiler/translator/osinclude.h" +#include "common/tls.h" + +#include +#include +#include -OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX; +TLSIndex PoolIndex = TLS_INVALID_INDEX; bool InitializePoolIndex() { - assert(PoolIndex == OS_INVALID_TLS_INDEX); + assert(PoolIndex == TLS_INVALID_INDEX); - PoolIndex = OS_AllocTLSIndex(); - return PoolIndex != OS_INVALID_TLS_INDEX; + PoolIndex = CreateTLSIndex(); + return PoolIndex != TLS_INVALID_INDEX; } void FreePoolIndex() { - assert(PoolIndex != OS_INVALID_TLS_INDEX); + assert(PoolIndex != TLS_INVALID_INDEX); - OS_FreeTLSIndex(PoolIndex); - PoolIndex = OS_INVALID_TLS_INDEX; + DestroyTLSIndex(PoolIndex); + PoolIndex = TLS_INVALID_INDEX; } TPoolAllocator* GetGlobalPoolAllocator() { - assert(PoolIndex != OS_INVALID_TLS_INDEX); - return static_cast(OS_GetTLSValue(PoolIndex)); + assert(PoolIndex != TLS_INVALID_INDEX); + return static_cast(GetTLSValue(PoolIndex)); } void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator) { - assert(PoolIndex != OS_INVALID_TLS_INDEX); - OS_SetTLSValue(PoolIndex, poolAllocator); + assert(PoolIndex != TLS_INVALID_INDEX); + SetTLSValue(PoolIndex, poolAllocator); } // diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp index 92e5dbbfe1..e381c32690 100644 --- a/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp @@ -8,70 +8,22 @@ #include "compiler/translator/RemoveTree.h" // -// Code to recursively delete the intermediate tree. +// Code to delete the intermediate tree. // - -class RemoveTree : public TIntermTraverser -{ -public: - RemoveTree() : TIntermTraverser(false, false, true) - { - } - -protected: - void visitSymbol(TIntermSymbol*); - void visitConstantUnion(TIntermConstantUnion*); - bool visitBinary(Visit visit, TIntermBinary*); - bool visitUnary(Visit visit, TIntermUnary*); - bool visitSelection(Visit visit, TIntermSelection*); - bool visitAggregate(Visit visit, TIntermAggregate*); -}; - -void RemoveTree::visitSymbol(TIntermSymbol* node) -{ - delete node; -} - -bool RemoveTree::visitBinary(Visit visit, TIntermBinary* node) -{ - delete node; - - return true; -} - -bool RemoveTree::visitUnary(Visit visit, TIntermUnary* node) -{ - delete node; - - return true; -} - -bool RemoveTree::visitAggregate(Visit visit, TIntermAggregate* node) +void RemoveAllTreeNodes(TIntermNode* root) { - delete node; + std::queue nodeQueue; - return true; -} + nodeQueue.push(root); -bool RemoveTree::visitSelection(Visit visit, TIntermSelection* node) -{ - delete node; + while (!nodeQueue.empty()) + { + TIntermNode *node = nodeQueue.front(); + nodeQueue.pop(); - return true; -} - -void RemoveTree::visitConstantUnion(TIntermConstantUnion* node) -{ - delete node; -} - -// -// Entry point. -// -void RemoveAllTreeNodes(TIntermNode* root) -{ - RemoveTree it; + node->enqueueChildren(&nodeQueue); - root->traverse(&it); + delete node; + } } diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp index 48e87cd57a..b03beb5c6c 100644 --- a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp @@ -14,6 +14,24 @@ namespace sh { +namespace +{ + +class ElseBlockRewriter : public TIntermTraverser +{ + public: + ElseBlockRewriter(); + + protected: + bool visitAggregate(Visit visit, TIntermAggregate *aggregate); + + private: + int mTemporaryIndex; + const TType *mFunctionType; + + TIntermNode *rewriteSelection(TIntermSelection *selection); +}; + TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type) { TType variableType(type, EbpHigh, EvqInternal); @@ -36,25 +54,45 @@ TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand) return unary; } +ElseBlockRewriter::ElseBlockRewriter() + : TIntermTraverser(true, false, true, false), + mTemporaryIndex(0), + mFunctionType(NULL) +{} + bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node) { switch (node->getOp()) { case EOpSequence: + if (visit == PostVisit) { - for (size_t statementIndex = 0; statementIndex != node->getSequence().size(); statementIndex++) + for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); statementIndex++) { - TIntermNode *statement = node->getSequence()[statementIndex]; + TIntermNode *statement = (*node->getSequence())[statementIndex]; TIntermSelection *selection = statement->getAsSelectionNode(); if (selection && selection->getFalseBlock() != NULL) { - node->getSequence()[statementIndex] = rewriteSelection(selection); + // Check for if / else if + TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode(); + if (elseIfBranch) + { + selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch)); + delete elseIfBranch; + } + + (*node->getSequence())[statementIndex] = rewriteSelection(selection); delete selection; } } } break; + case EOpFunction: + // Store the current function context (see comment below) + mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL); + break; + default: break; } @@ -63,32 +101,54 @@ bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node) TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection) { - ASSERT(selection->getFalseBlock() != NULL); + ASSERT(selection != NULL); TString temporaryName = "cond_" + str(mTemporaryIndex++); TIntermTyped *typedCondition = selection->getCondition()->getAsTyped(); TType resultType(EbtBool, EbpUndefined); - TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool); - TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool); - TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool); - TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA, + TIntermSymbol *conditionSymbolInit = MakeNewTemporary(temporaryName, EbtBool); + TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolInit, typedCondition, resultType); - TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB); - TIntermSelection *falseBlock = new TIntermSelection(negatedCondition, - selection->getFalseBlock(), NULL); - TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC, - selection->getTrueBlock(), falseBlock); + TIntermNode *negatedElse = NULL; + + TIntermSelection *falseBlock = NULL; + + if (selection->getFalseBlock()) + { + // crbug.com/346463 + // D3D generates error messages claiming a function has no return value, when rewriting + // an if-else clause that returns something non-void in a function. By appending dummy + // returns (that are unreachable) we can silence this compile error. + if (mFunctionType && mFunctionType->getBasicType() != EbtVoid) + { + TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() : + mFunctionType->getBasicString(); + TString rawText = "return (" + typeString + ")0"; + negatedElse = new TIntermRaw(*mFunctionType, rawText); + } + + TIntermSymbol *conditionSymbolElse = MakeNewTemporary(temporaryName, EbtBool); + TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse); + falseBlock = new TIntermSelection(negatedCondition, + selection->getFalseBlock(), negatedElse); + } + + TIntermSymbol *conditionSymbolSel = MakeNewTemporary(temporaryName, EbtBool); + TIntermSelection *newSelection = new TIntermSelection(conditionSymbolSel, + selection->getTrueBlock(), falseBlock); TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration); - declaration->getSequence().push_back(storeCondition); + declaration->getSequence()->push_back(storeCondition); TIntermAggregate *block = new TIntermAggregate(EOpSequence); - block->getSequence().push_back(declaration); - block->getSequence().push_back(newIfElse); + block->getSequence()->push_back(declaration); + block->getSequence()->push_back(newSelection); return block; } +} + void RewriteElseBlocks(TIntermNode *node) { ElseBlockRewriter rewriter; diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h index 10221335ce..39963d6a82 100644 --- a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h +++ b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h @@ -15,23 +15,6 @@ namespace sh { -class ElseBlockRewriter : public TIntermTraverser -{ - public: - ElseBlockRewriter() - : TIntermTraverser(false, false, true, false) - , mTemporaryIndex(0) - {} - - protected: - bool visitAggregate(Visit visit, TIntermAggregate *aggregate); - - private: - int mTemporaryIndex; - - TIntermNode *rewriteSelection(TIntermSelection *selection); -}; - void RewriteElseBlocks(TIntermNode *node); } diff --git a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp new file mode 100644 index 0000000000..3a179f7499 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp @@ -0,0 +1,266 @@ +// +// Copyright (c) 2002-2014 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/ScalarizeVecAndMatConstructorArgs.h" +#include "compiler/translator/compilerdebug.h" + +#include + +#include "common/angleutils.h" + +namespace +{ + +bool ContainsMatrixNode(const TIntermSequence &sequence) +{ + for (size_t ii = 0; ii < sequence.size(); ++ii) + { + TIntermTyped *node = sequence[ii]->getAsTyped(); + if (node && node->isMatrix()) + return true; + } + return false; +} + +bool ContainsVectorNode(const TIntermSequence &sequence) +{ + for (size_t ii = 0; ii < sequence.size(); ++ii) + { + TIntermTyped *node = sequence[ii]->getAsTyped(); + if (node && node->isVector()) + return true; + } + return false; +} + +TIntermConstantUnion *ConstructIndexNode(int index) +{ + ConstantUnion *u = new ConstantUnion[1]; + u[0].setIConst(index); + + TType type(EbtInt, EbpUndefined, EvqConst, 1); + TIntermConstantUnion *node = new TIntermConstantUnion(u, type); + return node; +} + +TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index) +{ + TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); + binary->setLeft(symbolNode); + TIntermConstantUnion *indexNode = ConstructIndexNode(index); + binary->setRight(indexNode); + return binary; +} + +TIntermBinary *ConstructMatrixIndexBinaryNode( + TIntermSymbol *symbolNode, int colIndex, int rowIndex) +{ + TIntermBinary *colVectorNode = + ConstructVectorIndexBinaryNode(symbolNode, colIndex); + + TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); + binary->setLeft(colVectorNode); + TIntermConstantUnion *rowIndexNode = ConstructIndexNode(rowIndex); + binary->setRight(rowIndexNode); + return binary; +} + +} // namespace anonymous + +bool ScalarizeVecAndMatConstructorArgs::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (visit == PreVisit) + { + switch (node->getOp()) + { + case EOpSequence: + mSequenceStack.push_back(TIntermSequence()); + { + for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); + iter != node->getSequence()->end(); ++iter) + { + TIntermNode *child = *iter; + ASSERT(child != NULL); + child->traverse(this); + mSequenceStack.back().push_back(child); + } + } + if (mSequenceStack.back().size() > node->getSequence()->size()) + { + node->getSequence()->clear(); + *(node->getSequence()) = mSequenceStack.back(); + } + mSequenceStack.pop_back(); + return false; + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + if (ContainsMatrixNode(*(node->getSequence()))) + scalarizeArgs(node, false, true); + break; + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + if (ContainsVectorNode(*(node->getSequence()))) + scalarizeArgs(node, true, false); + break; + default: + break; + } + } + return true; +} + +void ScalarizeVecAndMatConstructorArgs::scalarizeArgs( + TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix) +{ + ASSERT(aggregate); + int size = 0; + switch (aggregate->getOp()) + { + case EOpConstructVec2: + case EOpConstructBVec2: + case EOpConstructIVec2: + size = 2; + break; + case EOpConstructVec3: + case EOpConstructBVec3: + case EOpConstructIVec3: + size = 3; + break; + case EOpConstructVec4: + case EOpConstructBVec4: + case EOpConstructIVec4: + case EOpConstructMat2: + size = 4; + break; + case EOpConstructMat3: + size = 9; + break; + case EOpConstructMat4: + size = 16; + break; + default: + break; + } + TIntermSequence *sequence = aggregate->getSequence(); + TIntermSequence original(*sequence); + sequence->clear(); + for (size_t ii = 0; ii < original.size(); ++ii) + { + ASSERT(size > 0); + TIntermTyped *node = original[ii]->getAsTyped(); + ASSERT(node); + TString varName = createTempVariable(node); + if (node->isScalar()) + { + TIntermSymbol *symbolNode = + new TIntermSymbol(-1, varName, node->getType()); + sequence->push_back(symbolNode); + size--; + } + else if (node->isVector()) + { + if (scalarizeVector) + { + int repeat = std::min(size, node->getNominalSize()); + size -= repeat; + for (int index = 0; index < repeat; ++index) + { + TIntermSymbol *symbolNode = + new TIntermSymbol(-1, varName, node->getType()); + TIntermBinary *newNode = ConstructVectorIndexBinaryNode( + symbolNode, index); + sequence->push_back(newNode); + } + } + else + { + TIntermSymbol *symbolNode = + new TIntermSymbol(-1, varName, node->getType()); + sequence->push_back(symbolNode); + size -= node->getNominalSize(); + } + } + else + { + ASSERT(node->isMatrix()); + if (scalarizeMatrix) + { + int colIndex = 0, rowIndex = 0; + int repeat = std::min(size, node->getCols() * node->getRows()); + size -= repeat; + while (repeat > 0) + { + TIntermSymbol *symbolNode = + new TIntermSymbol(-1, varName, node->getType()); + TIntermBinary *newNode = ConstructMatrixIndexBinaryNode( + symbolNode, colIndex, rowIndex); + sequence->push_back(newNode); + rowIndex++; + if (rowIndex >= node->getRows()) + { + rowIndex = 0; + colIndex++; + } + repeat--; + } + } + else + { + TIntermSymbol *symbolNode = + new TIntermSymbol(-1, varName, node->getType()); + sequence->push_back(symbolNode); + size -= node->getCols() * node->getRows(); + } + } + } +} + +TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *original) +{ + TString tempVarName = "_webgl_tmp_"; + if (original->isScalar()) + { + tempVarName += "scalar_"; + } + else if (original->isVector()) + { + tempVarName += "vec_"; + } + else + { + ASSERT(original->isMatrix()); + tempVarName += "mat_"; + } + tempVarName += Str(mTempVarCount).c_str(); + mTempVarCount++; + + ASSERT(original); + TType type = original->getType(); + type.setQualifier(EvqTemporary); + + TIntermBinary *init = new TIntermBinary(EOpInitialize); + TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type); + init->setLeft(symbolNode); + init->setRight(original); + init->setType(type); + + TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration); + decl->getSequence()->push_back(init); + + ASSERT(mSequenceStack.size() > 0); + TIntermSequence &sequence = mSequenceStack.back(); + sequence.push_back(decl); + + return tempVarName; +} diff --git a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h new file mode 100644 index 0000000000..6aeb0c4f60 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2002-2014 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. +// + +#ifndef COMPILER_TRANSLATOR_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS_H_ +#define COMPILER_TRANSLATOR_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS_H_ + +#include "compiler/translator/intermediate.h" + +class ScalarizeVecAndMatConstructorArgs : public TIntermTraverser +{ + public: + ScalarizeVecAndMatConstructorArgs() + : mTempVarCount(0) {} + + protected: + virtual bool visitAggregate(Visit visit, TIntermAggregate *node); + + private: + void scalarizeArgs(TIntermAggregate *aggregate, + bool scalarizeVector, bool scalarizeMatrix); + + // If we have the following code: + // mat4 m(0); + // vec4 v(1, m); + // We will rewrite to: + // mat4 m(0); + // mat4 _webgl_tmp_mat_0 = m; + // vec4 v(1, _webgl_tmp_mat_0[0][0], _webgl_tmp_mat_0[0][1], _webgl_tmp_mat_0[0][2]); + // This function is to create nodes for "mat4 _webgl_tmp_mat_0 = m;" and insert it to + // the code sequence. + // Return the temporary variable name. + TString createTempVariable(TIntermTyped *original); + + std::vector mSequenceStack; + int mTempVarCount; +}; + +#endif // COMPILER_TRANSLATOR_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ShHandle.h b/src/3rdparty/angle/src/compiler/translator/ShHandle.h deleted file mode 100644 index 54ae27852d..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/ShHandle.h +++ /dev/null @@ -1,179 +0,0 @@ -// -// Copyright (c) 2002-2012 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. -// - -#ifndef _SHHANDLE_INCLUDED_ -#define _SHHANDLE_INCLUDED_ - -// -// Machine independent part of the compiler private objects -// sent as ShHandle to the driver. -// -// This should not be included by driver code. -// - -#include "GLSLANG/ShaderLang.h" - -#include "compiler/translator/BuiltInFunctionEmulator.h" -#include "compiler/translator/ExtensionBehavior.h" -#include "compiler/translator/HashNames.h" -#include "compiler/translator/InfoSink.h" -#include "compiler/translator/SymbolTable.h" -#include "compiler/translator/VariableInfo.h" -#include "third_party/compiler/ArrayBoundsClamper.h" - -class LongNameMap; -class TCompiler; -class TDependencyGraph; -class TranslatorHLSL; - -// -// Helper function to identify specs that are based on the WebGL spec, -// like the CSS Shaders spec. -// -bool isWebGLBasedSpec(ShShaderSpec spec); - -// -// The base class used to back handles returned to the driver. -// -class TShHandleBase { -public: - TShHandleBase(); - virtual ~TShHandleBase(); - virtual TCompiler* getAsCompiler() { return 0; } - virtual TranslatorHLSL* getAsTranslatorHLSL() { return 0; } - -protected: - // Memory allocator. Allocates and tracks memory required by the compiler. - // Deallocates all memory when compiler is destructed. - TPoolAllocator allocator; -}; - -// -// The base class for the machine dependent compiler to derive from -// for managing object code from the compile. -// -class TCompiler : public TShHandleBase { -public: - TCompiler(ShShaderType type, ShShaderSpec spec); - virtual ~TCompiler(); - virtual TCompiler* getAsCompiler() { return this; } - - bool Init(const ShBuiltInResources& resources); - bool compile(const char* const shaderStrings[], - size_t numStrings, - int compileOptions); - - // Get results of the last compilation. - TInfoSink& getInfoSink() { return infoSink; } - const TVariableInfoList& getAttribs() const { return attribs; } - const TVariableInfoList& getUniforms() const { return uniforms; } - const TVariableInfoList& getVaryings() const { return varyings; } - int getMappedNameMaxLength() const; - - ShHashFunction64 getHashFunction() const { return hashFunction; } - NameMap& getNameMap() { return nameMap; } - TSymbolTable& getSymbolTable() { return symbolTable; } - -protected: - ShShaderType getShaderType() const { return shaderType; } - ShShaderSpec getShaderSpec() const { return shaderSpec; } - // Initialize symbol-table with built-in symbols. - bool InitBuiltInSymbolTable(const ShBuiltInResources& resources); - // Clears the results from the previous compilation. - void clearResults(); - // Return true if function recursion is detected or call depth exceeded. - bool detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth); - // Rewrites a shader's intermediate tree according to the CSS Shaders spec. - void rewriteCSSShader(TIntermNode* root); - // Returns true if the given shader does not exceed the minimum - // functionality mandated in GLSL 1.0 spec Appendix A. - bool validateLimitations(TIntermNode* root); - // Collect info for all attribs, uniforms, varyings. - void collectVariables(TIntermNode* root); - // Map long variable names into shorter ones. - void mapLongVariableNames(TIntermNode* root); - // Translate to object code. - virtual void translate(TIntermNode* root) = 0; - // Returns true if, after applying the packing rules in the GLSL 1.017 spec - // Appendix A, section 7, the shader does not use too many uniforms. - bool enforcePackingRestrictions(); - // Insert statements to initialize varyings without static use in the beginning - // of main(). It is to work around a Mac driver where such varyings in a vertex - // shader may be optimized out incorrectly at compile time, causing a link failure. - // This function should only be applied to vertex shaders. - void initializeVaryingsWithoutStaticUse(TIntermNode* root); - // Insert gl_Position = vec4(0,0,0,0) to the beginning of main(). - // It is to work around a Linux driver bug where missing this causes compile failure - // while spec says it is allowed. - // This function should only be applied to vertex shaders. - void initializeGLPosition(TIntermNode* root); - // Returns true if the shader passes the restrictions that aim to prevent timing attacks. - bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph); - // Returns true if the shader does not use samplers. - bool enforceVertexShaderTimingRestrictions(TIntermNode* root); - // Returns true if the shader does not use sampler dependent values to affect control - // flow or in operations whose time can depend on the input values. - bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph); - // Return true if the maximum expression complexity below the limit. - bool limitExpressionComplexity(TIntermNode* root); - // Get built-in extensions with default behavior. - const TExtensionBehavior& getExtensionBehavior() const; - // Get the resources set by InitBuiltInSymbolTable - const ShBuiltInResources& getResources() const; - - const ArrayBoundsClamper& getArrayBoundsClamper() const; - ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const; - const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const; - -private: - ShShaderType shaderType; - ShShaderSpec shaderSpec; - - int maxUniformVectors; - int maxExpressionComplexity; - int maxCallStackDepth; - - ShBuiltInResources compileResources; - - // Built-in symbol table for the given language, spec, and resources. - // It is preserved from compile-to-compile. - TSymbolTable symbolTable; - // Built-in extensions with default behavior. - TExtensionBehavior extensionBehavior; - bool fragmentPrecisionHigh; - - ArrayBoundsClamper arrayBoundsClamper; - ShArrayIndexClampingStrategy clampingStrategy; - BuiltInFunctionEmulator builtInFunctionEmulator; - - // Results of compilation. - TInfoSink infoSink; // Output sink. - TVariableInfoList attribs; // Active attributes in the compiled shader. - TVariableInfoList uniforms; // Active uniforms in the compiled shader. - TVariableInfoList varyings; // Varyings in the compiled shader. - - // Cached copy of the ref-counted singleton. - LongNameMap* longNameMap; - - // name hashing. - ShHashFunction64 hashFunction; - NameMap nameMap; -}; - -// -// This is the interface between the machine independent code -// and the machine dependent code. -// -// The machine dependent code should derive from the classes -// above. Then Construct*() and Delete*() will create and -// destroy the machine dependent objects, which contain the -// above machine independent information. -// -TCompiler* ConstructCompiler( - ShShaderType type, ShShaderSpec spec, ShShaderOutput output); -void DeleteCompiler(TCompiler*); - -#endif // _SHHANDLE_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp index 608237860c..6a801eacfe 100644 --- a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -11,11 +11,14 @@ #include "GLSLANG/ShaderLang.h" +#include "compiler/translator/Compiler.h" #include "compiler/translator/InitializeDll.h" -#include "compiler/preprocessor/length_limits.h" -#include "compiler/translator/ShHandle.h" +#include "compiler/translator/length_limits.h" #include "compiler/translator/TranslatorHLSL.h" #include "compiler/translator/VariablePacker.h" +#include "angle_gl.h" + +static bool isInitialized = false; // // This is the platform independent interface between an OGL driver @@ -43,14 +46,62 @@ static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue return (expectedValue == mappedNameMaxLength); } +template +static const sh::ShaderVariable *ReturnVariable(const std::vector &infoList, int index) +{ + if (index < 0 || static_cast(index) >= infoList.size()) + { + return NULL; + } + + return &infoList[index]; +} + +static const sh::ShaderVariable *GetVariable(const TCompiler *compiler, ShShaderInfo varType, int index) +{ + switch (varType) + { + case SH_ACTIVE_ATTRIBUTES: + return ReturnVariable(compiler->getAttributes(), index); + case SH_ACTIVE_UNIFORMS: + return ReturnVariable(compiler->getExpandedUniforms(), index); + case SH_VARYINGS: + return ReturnVariable(compiler->getExpandedVaryings(), index); + default: + UNREACHABLE(); + return NULL; + } +} + +static ShPrecisionType ConvertPrecision(sh::GLenum precision) +{ + switch (precision) + { + case GL_HIGH_FLOAT: + case GL_HIGH_INT: + return SH_PRECISION_HIGHP; + case GL_MEDIUM_FLOAT: + case GL_MEDIUM_INT: + return SH_PRECISION_MEDIUMP; + case GL_LOW_FLOAT: + case GL_LOW_INT: + return SH_PRECISION_LOWP; + default: + return SH_PRECISION_UNDEFINED; + } +} + // // Driver must call this first, once, before doing any other compiler operations. // Subsequent calls to this function are no-op. // int ShInitialize() { - static const bool kInitialized = InitProcess(); - return kInitialized ? 1 : 0; + if (!isInitialized) + { + isInitialized = InitProcess(); + } + return isInitialized ? 1 : 0; } // @@ -58,7 +109,11 @@ int ShInitialize() // int ShFinalize() { - DetachProcess(); + if (isInitialized) + { + DetachProcess(); + isInitialized = false; + } return 1; } @@ -83,10 +138,17 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) resources->ARB_texture_rectangle = 0; resources->EXT_draw_buffers = 0; resources->EXT_frag_depth = 0; + resources->EXT_shader_texture_lod = 0; // Disable highp precision in fragment shader by default. resources->FragmentPrecisionHigh = 0; + // GLSL ES 3.0 constants. + resources->MaxVertexOutputVectors = 16; + resources->MaxFragmentInputVectors = 15; + resources->MinProgramTexelOffset = -8; + resources->MaxProgramTexelOffset = 7; + // Disable name hashing by default. resources->HashFunction = NULL; @@ -99,7 +161,7 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) // // Driver calls these to create and destroy compiler objects. // -ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec, +ShHandle ShConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output, const ShBuiltInResources* resources) { @@ -128,8 +190,25 @@ void ShDestruct(ShHandle handle) DeleteCompiler(base->getAsCompiler()); } +void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString) +{ + if (!handle || !outString) + { + return; + } + + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + if (!compiler) + { + return; + } + + strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen); + outString[outStringLen - 1] = '\0'; +} // -// Do an actual compile on the given strings. The result is left +// Do an actual compile on the given strings. The result is left // in the given compile object. // // Return: The return value of ShCompile is really boolean, indicating @@ -171,30 +250,30 @@ void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params) *params = compiler->getInfoSink().obj.size() + 1; break; case SH_ACTIVE_UNIFORMS: - *params = compiler->getUniforms().size(); + *params = compiler->getExpandedUniforms().size(); break; case SH_ACTIVE_UNIFORM_MAX_LENGTH: - *params = 1 + MAX_SYMBOL_NAME_LEN; + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); break; case SH_ACTIVE_ATTRIBUTES: - *params = compiler->getAttribs().size(); + *params = compiler->getAttributes().size(); break; case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: - *params = 1 + MAX_SYMBOL_NAME_LEN; + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); break; case SH_VARYINGS: - *params = compiler->getVaryings().size(); + *params = compiler->getExpandedVaryings().size(); break; case SH_VARYING_MAX_LENGTH: - *params = 1 + MAX_SYMBOL_NAME_LEN; + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); break; case SH_MAPPED_NAME_MAX_LENGTH: // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to // handle array and struct dereferences. - *params = 1 + MAX_SYMBOL_NAME_LEN; + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); break; case SH_NAME_MAX_LENGTH: - *params = 1 + MAX_SYMBOL_NAME_LEN; + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); break; case SH_HASHED_NAME_MAX_LENGTH: if (compiler->getHashFunction() == NULL) { @@ -203,12 +282,22 @@ void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params) // 64 bits hashing output requires 16 bytes for hex // representation. const char HashedNamePrefix[] = HASHED_NAME_PREFIX; + (void)HashedNamePrefix; *params = 16 + sizeof(HashedNamePrefix); } break; case SH_HASHED_NAMES_COUNT: *params = compiler->getNameMap().size(); break; + case SH_SHADER_VERSION: + *params = compiler->getShaderVersion(); + break; + case SH_RESOURCES_STRING_LENGTH: + *params = compiler->getBuiltInResourcesString().length() + 1; + break; + case SH_OUTPUT_TYPE: + *params = compiler->getOutputType(); + break; default: UNREACHABLE(); } } @@ -250,7 +339,7 @@ void ShGetVariableInfo(const ShHandle handle, int index, size_t* length, int* size, - ShDataType* type, + sh::GLenum* type, ShPrecisionType* precision, int* staticUse, char* name, @@ -267,47 +356,32 @@ void ShGetVariableInfo(const ShHandle handle, if (compiler == 0) return; - const TVariableInfoList& varList = - varType == SH_ACTIVE_ATTRIBUTES ? compiler->getAttribs() : - (varType == SH_ACTIVE_UNIFORMS ? compiler->getUniforms() : - compiler->getVaryings()); - if (index < 0 || index >= static_cast(varList.size())) + const sh::ShaderVariable *varInfo = GetVariable(compiler, varType, index); + if (!varInfo) + { return; - - const TVariableInfo& varInfo = varList[index]; - if (length) *length = varInfo.name.size(); - *size = varInfo.size; - *type = varInfo.type; - switch (varInfo.precision) { - case EbpLow: - *precision = SH_PRECISION_LOWP; - break; - case EbpMedium: - *precision = SH_PRECISION_MEDIUMP; - break; - case EbpHigh: - *precision = SH_PRECISION_HIGHP; - break; - default: - // Some types does not support precision, for example, boolean. - *precision = SH_PRECISION_UNDEFINED; - break; } - *staticUse = varInfo.staticUse ? 1 : 0; + + if (length) *length = varInfo->name.size(); + *size = varInfo->elementCount(); + *type = varInfo->type; + *precision = ConvertPrecision(varInfo->precision); + *staticUse = varInfo->staticUse ? 1 : 0; // This size must match that queried by // SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH // in ShGetInfo, below. - size_t variableLength = 1 + MAX_SYMBOL_NAME_LEN; + size_t variableLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); ASSERT(checkVariableMaxLengths(handle, variableLength)); - strncpy(name, varInfo.name.c_str(), variableLength); + strncpy(name, varInfo->name.c_str(), variableLength); name[variableLength - 1] = 0; - if (mappedName) { + if (mappedName) + { // This size must match that queried by // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below. - size_t maxMappedNameLength = 1 + MAX_SYMBOL_NAME_LEN; + size_t maxMappedNameLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength)); - strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength); + strncpy(mappedName, varInfo->mappedName.c_str(), maxMappedNameLength); mappedName[maxMappedNameLength - 1] = 0; } } @@ -369,6 +443,18 @@ void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params) case SH_ACTIVE_UNIFORMS_ARRAY: *params = (void*)&translator->getUniforms(); break; + case SH_ACTIVE_INTERFACE_BLOCKS_ARRAY: + *params = (void*)&translator->getInterfaceBlocks(); + break; + case SH_ACTIVE_OUTPUT_VARIABLES_ARRAY: + *params = (void*)&translator->getOutputVariables(); + break; + case SH_ACTIVE_ATTRIBUTES_ARRAY: + *params = (void*)&translator->getAttributes(); + break; + case SH_ACTIVE_VARYINGS_ARRAY: + *params = (void*)&translator->getVaryings(); + break; default: UNREACHABLE(); } } @@ -379,12 +465,62 @@ int ShCheckVariablesWithinPackingLimits( if (varInfoArraySize == 0) return 1; ASSERT(varInfoArray); - TVariableInfoList variables; + std::vector variables; for (size_t ii = 0; ii < varInfoArraySize; ++ii) { - TVariableInfo var(varInfoArray[ii].type, varInfoArray[ii].size); + sh::ShaderVariable var(varInfoArray[ii].type, (sh::GLenum)0, "", varInfoArray[ii].size); variables.push_back(var); } VariablePacker packer; return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0; } + +bool ShGetInterfaceBlockRegister(const ShHandle handle, + const char *interfaceBlockName, + unsigned int *indexOut) +{ + if (!handle || !interfaceBlockName || !indexOut) + { + return false; + } + + TShHandleBase* base = static_cast(handle); + TranslatorHLSL* translator = base->getAsTranslatorHLSL(); + if (!translator) + { + return false; + } + + if (!translator->hasInterfaceBlock(interfaceBlockName)) + { + return false; + } + + *indexOut = translator->getInterfaceBlockRegister(interfaceBlockName); + return true; +} + +bool ShGetUniformRegister(const ShHandle handle, + const char *uniformName, + unsigned int *indexOut) +{ + if (!handle || !uniformName || !indexOut) + { + return false; + } + + TShHandleBase* base = static_cast(handle); + TranslatorHLSL* translator = base->getAsTranslatorHLSL(); + if (!translator) + { + return false; + } + + if (!translator->hasUniform(uniformName)) + { + return false; + } + + *indexOut = translator->getUniformRegister(uniformName); + return true; +} diff --git a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp new file mode 100644 index 0000000000..365985c852 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp @@ -0,0 +1,477 @@ +// +// Copyright (c) 2014 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. +// +// StructureHLSL.cpp: +// Definitions of methods for HLSL translation of GLSL structures. +// + +#include "compiler/translator/StructureHLSL.h" +#include "common/utilities.h" +#include "compiler/translator/OutputHLSL.h" +#include "compiler/translator/Types.h" +#include "compiler/translator/util.h" +#include "compiler/translator/UtilsHLSL.h" + +namespace sh +{ + +Std140PaddingHelper::Std140PaddingHelper(const std::map &structElementIndexes) + : mPaddingCounter(0), + mElementIndex(0), + mStructElementIndexes(structElementIndexes) +{} + +int Std140PaddingHelper::prePadding(const TType &type) +{ + if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray()) + { + // no padding needed, HLSL will align the field to a new register + mElementIndex = 0; + return 0; + } + + const GLenum glType = GLVariableType(type); + const int numComponents = gl::VariableComponentCount(glType); + + if (numComponents >= 4) + { + // no padding needed, HLSL will align the field to a new register + mElementIndex = 0; + return 0; + } + + if (mElementIndex + numComponents > 4) + { + // no padding needed, HLSL will align the field to a new register + mElementIndex = numComponents; + return 0; + } + + const int alignment = numComponents == 3 ? 4 : numComponents; + const int paddingOffset = (mElementIndex % alignment); + const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0); + + mElementIndex += paddingCount; + mElementIndex += numComponents; + mElementIndex %= 4; + + return paddingCount; +} + +TString Std140PaddingHelper::prePaddingString(const TType &type) +{ + int paddingCount = prePadding(type); + + TString padding; + + for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++) + { + padding += " float pad_" + str(mPaddingCounter++) + ";\n"; + } + + return padding; +} + +TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking) +{ + if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct) + { + return ""; + } + + int numComponents = 0; + TStructure *structure = type.getStruct(); + + if (type.isMatrix()) + { + // This method can also be called from structureString, which does not use layout qualifiers. + // Thus, use the method parameter for determining the matrix packing. + // + // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we + // wish to always transpose GL matrices to play well with HLSL's matrix array indexing. + // + const bool isRowMajorMatrix = !useHLSLRowMajorPacking; + const GLenum glType = GLVariableType(type); + numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix); + } + else if (structure) + { + const TString &structName = QualifiedStructNameString(*structure, + useHLSLRowMajorPacking, true); + numComponents = mStructElementIndexes.find(structName)->second; + + if (numComponents == 0) + { + return ""; + } + } + else + { + const GLenum glType = GLVariableType(type); + numComponents = gl::VariableComponentCount(glType); + } + + TString padding; + for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++) + { + padding += " float pad_" + str(mPaddingCounter++) + ";\n"; + } + return padding; +} + +StructureHLSL::StructureHLSL() +{} + +TString StructureHLSL::defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing) +{ + if (useStd140Packing) + { + Std140PaddingHelper padHelper(mStd140StructElementIndexes); + return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper); + } + else + { + return define(structure, useHLSLRowMajorPacking, useStd140Packing, NULL); + } +} + +TString StructureHLSL::defineNameless(const TStructure &structure) +{ + return define(structure, false, false, NULL); +} + +TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking, + bool useStd140Packing, Std140PaddingHelper *padHelper) +{ + const TFieldList &fields = structure.fields(); + const bool isNameless = (structure.name() == ""); + const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, + useStd140Packing); + const TString declareString = (isNameless ? "struct" : "struct " + structName); + + TString string; + string += declareString + "\n" + "{\n"; + + for (unsigned int i = 0; i < fields.size(); i++) + { + const TField &field = *fields[i]; + const TType &fieldType = *field.type(); + const TStructure *fieldStruct = fieldType.getStruct(); + const TString &fieldTypeString = fieldStruct ? + QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking, + useStd140Packing) : + TypeString(fieldType); + + if (padHelper) + { + string += padHelper->prePaddingString(fieldType); + } + + string += " " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n"; + + if (padHelper) + { + string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking); + } + } + + // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable + string += (isNameless ? "} " : "};\n"); + + return string; +} + +void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters) +{ + if (name == "") + { + return; // Nameless structures don't have constructors + } + + if (type.getStruct() && mStructNames.find(name) != mStructNames.end()) + { + return; // Already added + } + + TType ctorType = type; + ctorType.clearArrayness(); + ctorType.setPrecision(EbpHigh); + ctorType.setQualifier(EvqTemporary); + + typedef std::vector ParameterArray; + ParameterArray ctorParameters; + + const TStructure* structure = type.getStruct(); + if (structure) + { + mStructNames.insert(name); + + // Add element index + storeStd140ElementIndex(*structure, false); + storeStd140ElementIndex(*structure, true); + + const TString &structString = defineQualified(*structure, false, false); + + if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end()) + { + // Add row-major packed struct for interface blocks + TString rowMajorString = "#pragma pack_matrix(row_major)\n" + + defineQualified(*structure, true, false) + + "#pragma pack_matrix(column_major)\n"; + + TString std140String = defineQualified(*structure, false, true); + TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" + + defineQualified(*structure, true, true) + + "#pragma pack_matrix(column_major)\n"; + + mStructDeclarations.push_back(structString); + mStructDeclarations.push_back(rowMajorString); + mStructDeclarations.push_back(std140String); + mStructDeclarations.push_back(std140RowMajorString); + } + + const TFieldList &fields = structure->fields(); + for (unsigned int i = 0; i < fields.size(); i++) + { + ctorParameters.push_back(*fields[i]->type()); + } + } + else if (parameters) + { + for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++) + { + ctorParameters.push_back((*parameter)->getAsTyped()->getType()); + } + } + else UNREACHABLE(); + + TString constructor; + + if (ctorType.getStruct()) + { + constructor += name + " " + name + "_ctor("; + } + else // Built-in type + { + constructor += TypeString(ctorType) + " " + name + "("; + } + + for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) + { + const TType &type = ctorParameters[parameter]; + + constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type); + + if (parameter < ctorParameters.size() - 1) + { + constructor += ", "; + } + } + + constructor += ")\n" + "{\n"; + + if (ctorType.getStruct()) + { + constructor += " " + name + " structure = {"; + } + else + { + constructor += " return " + TypeString(ctorType) + "("; + } + + if (ctorType.isMatrix() && ctorParameters.size() == 1) + { + int rows = ctorType.getRows(); + int cols = ctorType.getCols(); + const TType ¶meter = ctorParameters[0]; + + if (parameter.isScalar()) + { + for (int row = 0; row < rows; row++) + { + for (int col = 0; col < cols; col++) + { + constructor += TString((row == col) ? "x0" : "0.0"); + + if (row < rows - 1 || col < cols - 1) + { + constructor += ", "; + } + } + } + } + else if (parameter.isMatrix()) + { + for (int row = 0; row < rows; row++) + { + for (int col = 0; col < cols; col++) + { + if (row < parameter.getRows() && col < parameter.getCols()) + { + constructor += TString("x0") + "[" + str(row) + "][" + str(col) + "]"; + } + else + { + constructor += TString((row == col) ? "1.0" : "0.0"); + } + + if (row < rows - 1 || col < cols - 1) + { + constructor += ", "; + } + } + } + } + else + { + ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4); + + constructor += "x0"; + } + } + else + { + size_t remainingComponents = ctorType.getObjectSize(); + size_t parameterIndex = 0; + + while (remainingComponents > 0) + { + const TType ¶meter = ctorParameters[parameterIndex]; + const size_t parameterSize = parameter.getObjectSize(); + bool moreParameters = parameterIndex + 1 < ctorParameters.size(); + + constructor += "x" + str(parameterIndex); + + if (ctorType.getStruct()) + { + ASSERT(remainingComponents == parameterSize || moreParameters); + ASSERT(parameterSize <= remainingComponents); + + remainingComponents -= parameterSize; + } + else if (parameter.isScalar()) + { + remainingComponents -= parameter.getObjectSize(); + } + else if (parameter.isVector()) + { + if (remainingComponents == parameterSize || moreParameters) + { + ASSERT(parameterSize <= remainingComponents); + remainingComponents -= parameterSize; + } + else if (remainingComponents < static_cast(parameter.getNominalSize())) + { + switch (remainingComponents) + { + case 1: constructor += ".x"; break; + case 2: constructor += ".xy"; break; + case 3: constructor += ".xyz"; break; + case 4: constructor += ".xyzw"; break; + default: UNREACHABLE(); + } + + remainingComponents = 0; + } + else UNREACHABLE(); + } + else if (parameter.isMatrix()) + { + int column = 0; + while (remainingComponents > 0 && column < parameter.getCols()) + { + constructor += "[" + str(column) + "]"; + + if (remainingComponents < static_cast(parameter.getRows())) + { + switch (remainingComponents) + { + case 1: constructor += ".x"; break; + case 2: constructor += ".xy"; break; + case 3: constructor += ".xyz"; break; + default: UNREACHABLE(); + } + + remainingComponents = 0; + } + else + { + remainingComponents -= parameter.getRows(); + + if (remainingComponents > 0) + { + constructor += ", x" + str(parameterIndex); + } + } + + column++; + } + } + else UNREACHABLE(); + + if (moreParameters) + { + parameterIndex++; + } + + if (remainingComponents) + { + constructor += ", "; + } + } + } + + if (ctorType.getStruct()) + { + constructor += "};\n" + " return structure;\n" + "}\n"; + } + else + { + constructor += ");\n" + "}\n"; + } + + mConstructors.insert(constructor); +} + +std::string StructureHLSL::structsHeader() const +{ + TInfoSinkBase out; + + for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++) + { + out << mStructDeclarations[structIndex]; + } + + for (Constructors::const_iterator constructor = mConstructors.begin(); + constructor != mConstructors.end(); + constructor++) + { + out << *constructor; + } + + return out.str(); +} + +void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking) +{ + Std140PaddingHelper padHelper(mStd140StructElementIndexes); + const TFieldList &fields = structure.fields(); + + for (unsigned int i = 0; i < fields.size(); i++) + { + padHelper.prePadding(*fields[i]->type()); + } + + // Add remaining element index to the global map, for use with nested structs in standard layouts + const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true); + mStd140StructElementIndexes[structName] = padHelper.elementIndex(); +} + +} diff --git a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h new file mode 100644 index 0000000000..63fbaaaf8e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h @@ -0,0 +1,74 @@ +// +// Copyright (c) 2014 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. +// +// StructureHLSL.h: +// Interfaces of methods for HLSL translation of GLSL structures. +// + +#ifndef TRANSLATOR_STRUCTUREHLSL_H_ +#define TRANSLATOR_STRUCTUREHLSL_H_ + +#include "compiler/translator/Common.h" +#include "compiler/translator/intermediate.h" + +#include + +class TInfoSinkBase; +class TScopeBracket; + +namespace sh +{ + +// This helper class assists structure and interface block definitions in determining +// how to pack std140 structs within HLSL's packing rules. +class Std140PaddingHelper +{ + public: + explicit Std140PaddingHelper(const std::map &structElementIndexes); + + int elementIndex() const { return mElementIndex; } + int prePadding(const TType &type); + TString prePaddingString(const TType &type); + TString postPaddingString(const TType &type, bool useHLSLRowMajorPacking); + + private: + int mPaddingCounter; + int mElementIndex; + const std::map &mStructElementIndexes; +}; + +class StructureHLSL +{ + public: + StructureHLSL(); + + void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters); + std::string structsHeader() const; + + TString defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing); + static TString defineNameless(const TStructure &structure); + + Std140PaddingHelper getPaddingHelper() const { return Std140PaddingHelper(mStd140StructElementIndexes); } + + private: + std::map mStd140StructElementIndexes; + + typedef std::set StructNames; + StructNames mStructNames; + + typedef std::set Constructors; + Constructors mConstructors; + + typedef std::vector StructDeclarations; + StructDeclarations mStructDeclarations; + + void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking); + static TString define(const TStructure &structure, bool useHLSLRowMajorPacking, + bool useStd140Packing, Std140PaddingHelper *padHelper); +}; + +} + +#endif // COMPILER_STRUCTUREHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp index d04fe5d355..ae4fcaa6c3 100644 --- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -17,200 +17,220 @@ #include #include -#include -TType::TType(const TPublicType &p) : - type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize), structure(0) +int TSymbolTable::uniqueIdCounter = 0; + +// +// Functions have buried pointers to delete. +// +TFunction::~TFunction() { - if (p.userDef) - structure = p.userDef->getStruct(); + for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i) + delete (*i).type; } // -// Recursively generate mangled names. +// Symbol table levels are a map of pointers to symbols that have to be deleted. // -TString TType::buildMangledName() const +TSymbolTableLevel::~TSymbolTableLevel() { - TString mangledName; - if (isMatrix()) - mangledName += 'm'; - else if (isVector()) - mangledName += 'v'; - - switch (type) { - case EbtFloat: mangledName += 'f'; break; - case EbtInt: mangledName += 'i'; break; - case EbtBool: mangledName += 'b'; break; - case EbtSampler2D: mangledName += "s2"; break; - case EbtSamplerCube: mangledName += "sC"; break; - case EbtStruct: mangledName += structure->mangledName(); break; - default: break; - } - - mangledName += static_cast('0' + getNominalSize()); - if (isArray()) { - char buf[20]; - snprintf(buf, sizeof(buf), "%d", arraySize); - mangledName += '['; - mangledName += buf; - mangledName += ']'; - } - return mangledName; + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) + delete (*it).second; } -size_t TType::getObjectSize() const +bool TSymbolTableLevel::insert(TSymbol *symbol) { - size_t totalSize = 0; + symbol->setUniqueId(TSymbolTable::nextUniqueId()); - if (getBasicType() == EbtStruct) - totalSize = structure->objectSize(); - else if (matrix) - totalSize = size * size; - else - totalSize = size; - - if (isArray()) { - size_t arraySize = getArraySize(); - if (arraySize > INT_MAX / totalSize) - totalSize = INT_MAX; - else - totalSize *= arraySize; - } + // returning true means symbol was added to the table + tInsertResult result = level.insert(tLevelPair(symbol->getMangledName(), symbol)); - return totalSize; + return result.second; } -bool TStructure::containsArrays() const +TSymbol *TSymbolTableLevel::find(const TString &name) const { - for (size_t i = 0; i < mFields->size(); ++i) { - const TType* fieldType = (*mFields)[i]->type(); - if (fieldType->isArray() || fieldType->isStructureContainingArrays()) - return true; - } - return false; + tLevel::const_iterator it = level.find(name); + if (it == level.end()) + return 0; + else + return (*it).second; } -TString TStructure::buildMangledName() const +// +// Change all function entries in the table with the non-mangled name +// to be related to the provided built-in operation. This is a low +// performance operation, and only intended for symbol tables that +// live across a large number of compiles. +// +void TSymbolTableLevel::relateToOperator(const char *name, TOperator op) { - TString mangledName("struct-"); - mangledName += *mName; - for (size_t i = 0; i < mFields->size(); ++i) { - mangledName += '-'; - mangledName += (*mFields)[i]->type()->getMangledName(); + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) + { + if ((*it).second->isFunction()) + { + TFunction *function = static_cast((*it).second); + if (function->getName() == name) + function->relateToOperator(op); + } } - return mangledName; } -size_t TStructure::calculateObjectSize() const +// +// Change all function entries in the table with the non-mangled name +// to be related to the provided built-in extension. This is a low +// performance operation, and only intended for symbol tables that +// live across a large number of compiles. +// +void TSymbolTableLevel::relateToExtension(const char *name, const TString &ext) { - size_t size = 0; - for (size_t i = 0; i < mFields->size(); ++i) { - size_t fieldSize = (*mFields)[i]->type()->getObjectSize(); - if (fieldSize > INT_MAX - size) - size = INT_MAX; - else - size += fieldSize; + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) + { + TSymbol *symbol = it->second; + if (symbol->getName() == name) + symbol->relateToExtension(ext); } - return size; } -int TStructure::calculateDeepestNesting() const +TSymbol::TSymbol(const TSymbol ©Of) { - int maxNesting = 0; - for (size_t i = 0; i < mFields->size(); ++i) { - maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting()); - } - return 1 + maxNesting; + name = NewPoolTString(copyOf.name->c_str()); + uniqueId = copyOf.uniqueId; } -// -// Dump functions. -// - -void TVariable::dump(TInfoSink& infoSink) const +TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, bool *builtIn, bool *sameScope) { - infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString(); - if (type.isArray()) { - infoSink.debug << "[0]"; + int level = currentLevel(); + TSymbol *symbol; + + do + { + if (level == ESSL3_BUILTINS && shaderVersion != 300) + level--; + if (level == ESSL1_BUILTINS && shaderVersion != 100) + level--; + + symbol = table[level]->find(name); } - infoSink.debug << "\n"; -} + while (symbol == 0 && --level >= 0); -void TFunction::dump(TInfoSink &infoSink) const -{ - infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n"; -} + if (builtIn) + *builtIn = (level <= LAST_BUILTIN_LEVEL); + if (sameScope) + *sameScope = (level == currentLevel()); -void TSymbolTableLevel::dump(TInfoSink &infoSink) const -{ - tLevel::const_iterator it; - for (it = level.begin(); it != level.end(); ++it) - (*it).second->dump(infoSink); + return symbol; } -void TSymbolTable::dump(TInfoSink &infoSink) const +TSymbol *TSymbolTable::findBuiltIn(const TString &name, int shaderVersion) { - for (int level = currentLevel(); level >= 0; --level) { - infoSink.debug << "LEVEL " << level << "\n"; - table[level]->dump(infoSink); + for (int level = LAST_BUILTIN_LEVEL; level >= 0; level--) + { + if (level == ESSL3_BUILTINS && shaderVersion != 300) + level--; + if (level == ESSL1_BUILTINS && shaderVersion != 100) + level--; + + TSymbol *symbol = table[level]->find(name); + + if (symbol) + return symbol; } -} -// -// Functions have buried pointers to delete. -// -TFunction::~TFunction() -{ - for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i) - delete (*i).type; + return 0; } -// -// Symbol table levels are a map of pointers to symbols that have to be deleted. -// -TSymbolTableLevel::~TSymbolTableLevel() +TSymbolTable::~TSymbolTable() { - for (tLevel::iterator it = level.begin(); it != level.end(); ++it) - delete (*it).second; + while (table.size() > 0) + pop(); } -// -// Change all function entries in the table with the non-mangled name -// to be related to the provided built-in operation. This is a low -// performance operation, and only intended for symbol tables that -// live across a large number of compiles. -// -void TSymbolTableLevel::relateToOperator(const char* name, TOperator op) +void TSymbolTable::insertBuiltIn( + ESymbolLevel level, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5) { - tLevel::iterator it; - for (it = level.begin(); it != level.end(); ++it) { - if ((*it).second->isFunction()) { - TFunction* function = static_cast((*it).second); - if (function->getName() == name) - function->relateToOperator(op); - } + if (ptype1->getBasicType() == EbtGSampler2D) + { + bool gvec4 = (rvalue->getBasicType() == EbtGVec4); + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, + new TType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, + new TType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, + new TType(EbtUSampler2D), ptype2, ptype3, ptype4, ptype5); + return; + } + if (ptype1->getBasicType() == EbtGSampler3D) + { + bool gvec4 = (rvalue->getBasicType() == EbtGVec4); + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, + new TType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, + new TType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, + new TType(EbtUSampler3D), ptype2, ptype3, ptype4, ptype5); + return; + } + if (ptype1->getBasicType() == EbtGSamplerCube) + { + bool gvec4 = (rvalue->getBasicType() == EbtGVec4); + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, + new TType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, + new TType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, + new TType(EbtUSamplerCube), ptype2, ptype3, ptype4, ptype5); + return; + } + if (ptype1->getBasicType() == EbtGSampler2DArray) + { + bool gvec4 = (rvalue->getBasicType() == EbtGVec4); + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, + new TType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, + new TType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, + new TType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5); + return; } -} -// -// Change all function entries in the table with the non-mangled name -// to be related to the provided built-in extension. This is a low -// performance operation, and only intended for symbol tables that -// live across a large number of compiles. -// -void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext) -{ - for (tLevel::iterator it = level.begin(); it != level.end(); ++it) { - TSymbol* symbol = it->second; - if (symbol->getName() == name) - symbol->relateToExtension(ext); + TFunction *function = new TFunction(NewPoolTString(name), *rvalue); + + TType *types[] = {ptype1, ptype2, ptype3, ptype4, ptype5}; + for (size_t ii = 0; ii < sizeof(types) / sizeof(types[0]); ++ii) + { + if (types[ii]) + { + TParameter param = {NULL, types[ii]}; + function->addParameter(param); + } } + + insert(level, function); } -TSymbolTable::~TSymbolTable() +TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) { - for (size_t i = 0; i < table.size(); ++i) - delete table[i]; - for (size_t i = 0; i < precisionStack.size(); ++i) - delete precisionStack[i]; + if (!SupportsPrecision(type)) + return EbpUndefined; + + // unsigned integers use the same precision as signed + TBasicType baseType = (type == EbtUInt) ? EbtInt : type; + + int level = static_cast(precisionStack.size()) - 1; + assert(level >= 0); // Just to be safe. Should not happen. + // If we dont find anything we return this. Should we error check this? + TPrecision prec = EbpUndefined; + while (level >= 0) + { + PrecisionStackLevel::iterator it = precisionStack[level]->find(baseType); + if (it != precisionStack[level]->end()) + { + prec = (*it).second; + break; + } + level--; + } + return prec; } diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h index 6c7211f2a9..d3ddf19e34 100644 --- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h +++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -36,34 +36,62 @@ #include "compiler/translator/InfoSink.h" #include "compiler/translator/intermediate.h" -// -// Symbol base class. (Can build functions or variables out of these...) -// -class TSymbol { -public: +// Symbol base class. (Can build functions or variables out of these...) +class TSymbol +{ + public: POOL_ALLOCATOR_NEW_DELETE(); - TSymbol(const TString* n) : uniqueId(0), name(n) { } - virtual ~TSymbol() { /* don't delete name, it's from the pool */ } - - const TString& getName() const { return *name; } - virtual const TString& getMangledName() const { return getName(); } - virtual bool isFunction() const { return false; } - virtual bool isVariable() const { return false; } - void setUniqueId(int id) { uniqueId = id; } - int getUniqueId() const { return uniqueId; } - virtual void dump(TInfoSink &infoSink) const = 0; - void relateToExtension(const TString& ext) { extension = ext; } - const TString& getExtension() const { return extension; } - -private: + TSymbol(const TString *n) + : uniqueId(0), + name(n) + { + } + virtual ~TSymbol() + { + // don't delete name, it's from the pool + } + + const TString &getName() const + { + return *name; + } + virtual const TString &getMangledName() const + { + return getName(); + } + virtual bool isFunction() const + { + return false; + } + virtual bool isVariable() const + { + return false; + } + void setUniqueId(int id) + { + uniqueId = id; + } + int getUniqueId() const + { + return uniqueId; + } + void relateToExtension(const TString &ext) + { + extension = ext; + } + const TString &getExtension() const + { + return extension; + } + + private: DISALLOW_COPY_AND_ASSIGN(TSymbol); - int uniqueId; // For real comparing during code generation + int uniqueId; // For real comparing during code generation const TString *name; TString extension; }; -// // Variable class, meaning a symbol that's not a function. // // There could be a separate class heirarchy for Constant variables; @@ -72,20 +100,41 @@ private: // seem worth having separate classes, and "getConst" can't simply return // different values for different types polymorphically, so this is // just simple and pragmatic. -// -class TVariable : public TSymbol { -public: - TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0) { } - virtual ~TVariable() { } - virtual bool isVariable() const { return true; } - TType& getType() { return type; } - const TType& getType() const { return type; } - bool isUserType() const { return userType; } - void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); } - - virtual void dump(TInfoSink &infoSink) const; - - ConstantUnion* getConstPointer() +class TVariable : public TSymbol +{ + public: + TVariable(const TString *name, const TType &t, bool uT = false) + : TSymbol(name), + type(t), + userType(uT), + unionArray(0) + { + } + virtual ~TVariable() + { + } + virtual bool isVariable() const + { + return true; + } + TType &getType() + { + return type; + } + const TType &getType() const + { + return type; + } + bool isUserType() const + { + return userType; + } + void setQualifier(TQualifier qualifier) + { + type.setQualifier(qualifier); + } + + ConstantUnion *getConstPointer() { if (!unionArray) unionArray = new ConstantUnion[type.getObjectSize()]; @@ -93,9 +142,12 @@ public: return unionArray; } - ConstantUnion* getConstPointer() const { return unionArray; } + ConstantUnion *getConstPointer() const + { + return unionArray; + } - void shareConstPointer( ConstantUnion *constArray) + void shareConstPointer(ConstantUnion *constArray) { if (unionArray == constArray) return; @@ -104,71 +156,101 @@ public: unionArray = constArray; } -private: + private: DISALLOW_COPY_AND_ASSIGN(TVariable); TType type; bool userType; - // we are assuming that Pool Allocator will free the memory allocated to unionArray - // when this object is destroyed + // we are assuming that Pool Allocator will free the memory + // allocated to unionArray when this object is destroyed. ConstantUnion *unionArray; }; -// // The function sub-class of symbols and the parser will need to // share this definition of a function parameter. -// -struct TParameter { +struct TParameter +{ TString *name; - TType* type; + TType *type; }; -// // The function sub-class of a symbol. -// -class TFunction : public TSymbol { -public: - TFunction(TOperator o) : - TSymbol(0), - returnType(TType(EbtVoid, EbpUndefined)), - op(o), - defined(false) { } - TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) : - TSymbol(name), - returnType(retType), - mangledName(TFunction::mangleName(*name)), - op(tOp), - defined(false) { } +class TFunction : public TSymbol +{ + public: + TFunction(TOperator o) + : TSymbol(0), + returnType(TType(EbtVoid, EbpUndefined)), + op(o), + defined(false) + { + } + TFunction(const TString *name, const TType &retType, TOperator tOp = EOpNull) + : TSymbol(name), + returnType(retType), + mangledName(TFunction::mangleName(*name)), + op(tOp), + defined(false) + { + } virtual ~TFunction(); - virtual bool isFunction() const { return true; } + virtual bool isFunction() const + { + return true; + } - static TString mangleName(const TString& name) { return name + '('; } - static TString unmangleName(const TString& mangledName) + static TString mangleName(const TString &name) + { + return name + '('; + } + static TString unmangleName(const TString &mangledName) { return TString(mangledName.c_str(), mangledName.find_first_of('(')); } - void addParameter(TParameter& p) + void addParameter(TParameter &p) { parameters.push_back(p); mangledName = mangledName + p.type->getMangledName(); } - const TString& getMangledName() const { return mangledName; } - const TType& getReturnType() const { return returnType; } - - void relateToOperator(TOperator o) { op = o; } - TOperator getBuiltInOp() const { return op; } + const TString &getMangledName() const + { + return mangledName; + } + const TType &getReturnType() const + { + return returnType; + } - void setDefined() { defined = true; } - bool isDefined() { return defined; } + void relateToOperator(TOperator o) + { + op = o; + } + TOperator getBuiltInOp() const + { + return op; + } - size_t getParamCount() const { return parameters.size(); } - const TParameter& getParam(size_t i) const { return parameters[i]; } + void setDefined() + { + defined = true; + } + bool isDefined() + { + return defined; + } - virtual void dump(TInfoSink &infoSink) const; + size_t getParamCount() const + { + return parameters.size(); + } + const TParameter &getParam(size_t i) const + { + return parameters[i]; + } -private: + private: DISALLOW_COPY_AND_ASSIGN(TFunction); typedef TVector TParamList; @@ -179,79 +261,80 @@ private: bool defined; }; - -class TSymbolTableLevel { -public: - typedef TMap tLevel; - typedef tLevel::const_iterator const_iterator; - typedef const tLevel::value_type tLevelPair; - typedef std::pair tInsertResult; - - TSymbolTableLevel() { } - ~TSymbolTableLevel(); - - bool insert(const TString &name, TSymbol &symbol) +// Interface block name sub-symbol +class TInterfaceBlockName : public TSymbol +{ + public: + TInterfaceBlockName(const TString *name) + : TSymbol(name) { - // - // returning true means symbol was added to the table - // - tInsertResult result = level.insert(tLevelPair(name, &symbol)); - - return result.second; } - bool insert(TSymbol &symbol) + virtual ~TInterfaceBlockName() { - return insert(symbol.getMangledName(), symbol); } +}; - TSymbol* find(const TString& name) const - { - tLevel::const_iterator it = level.find(name); - if (it == level.end()) - return 0; - else - return (*it).second; - } +class TSymbolTableLevel +{ + public: + typedef TMap tLevel; + typedef tLevel::const_iterator const_iterator; + typedef const tLevel::value_type tLevelPair; + typedef std::pair tInsertResult; - const_iterator begin() const + TSymbolTableLevel() { - return level.begin(); } + ~TSymbolTableLevel(); - const_iterator end() const - { - return level.end(); - } + bool insert(TSymbol *symbol); - void relateToOperator(const char* name, TOperator op); - void relateToExtension(const char* name, const TString& ext); - void dump(TInfoSink &infoSink) const; + TSymbol *find(const TString &name) const; -protected: + void relateToOperator(const char *name, TOperator op); + void relateToExtension(const char *name, const TString &ext); + + protected: tLevel level; }; -class TSymbolTable { -public: - TSymbolTable() : uniqueId(0) +enum ESymbolLevel +{ + COMMON_BUILTINS = 0, + ESSL1_BUILTINS = 1, + ESSL3_BUILTINS = 2, + LAST_BUILTIN_LEVEL = ESSL3_BUILTINS, + GLOBAL_LEVEL = 3 +}; + +class TSymbolTable +{ + public: + TSymbolTable() { - // // The symbol table cannot be used until push() is called, but // the lack of an initial call to push() can be used to detect // that the symbol table has not been preloaded with built-ins. - // } + ~TSymbolTable(); - // // When the symbol table is initialized with the built-ins, there should // 'push' calls, so that built-ins are at level 0 and the shader // globals are at level 1. - // - bool isEmpty() { return table.size() == 0; } - bool atBuiltInLevel() { return table.size() == 1; } - bool atGlobalLevel() { return table.size() <= 2; } + bool isEmpty() + { + return table.empty(); + } + bool atBuiltInLevel() + { + return currentLevel() <= LAST_BUILTIN_LEVEL; + } + bool atGlobalLevel() + { + return currentLevel() <= GLOBAL_LEVEL; + } void push() { table.push_back(new TSymbolTableLevel); @@ -267,116 +350,80 @@ public: precisionStack.pop_back(); } - bool insert(TSymbol& symbol) + bool declare(TSymbol *symbol) { - symbol.setUniqueId(++uniqueId); - return table[currentLevel()]->insert(symbol); + return insert(currentLevel(), symbol); } - bool insertConstInt(const char *name, int value) + bool insert(ESymbolLevel level, TSymbol *symbol) { - TVariable *constant = new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); - constant->getConstPointer()->setIConst(value); - return insert(*constant); + return table[level]->insert(symbol); } - bool insertBuiltIn(TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0) + bool insertConstInt(ESymbolLevel level, const char *name, int value) { - TFunction *function = new TFunction(NewPoolTString(name), *rvalue); - - TParameter param1 = {NULL, ptype1}; - function->addParameter(param1); - - if(ptype2) - { - TParameter param2 = {NULL, ptype2}; - function->addParameter(param2); - } - - if(ptype3) - { - TParameter param3 = {NULL, ptype3}; - function->addParameter(param3); - } - - return insert(*function); + TVariable *constant = new TVariable( + NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); + constant->getConstPointer()->setIConst(value); + return insert(level, constant); } - TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0) - { - int level = currentLevel(); - TSymbol* symbol; - do { - symbol = table[level]->find(name); - --level; - } while (symbol == 0 && level >= 0); - level++; - if (builtIn) - *builtIn = level == 0; - if (sameScope) - *sameScope = level == currentLevel(); - return symbol; - } + void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, + TType *ptype4 = 0, TType *ptype5 = 0); - TSymbol* findBuiltIn(const TString &name) + TSymbol *find(const TString &name, int shaderVersion, + bool *builtIn = NULL, bool *sameScope = NULL); + TSymbol *findBuiltIn(const TString &name, int shaderVersion); + + TSymbolTableLevel *getOuterLevel() { - return table[0]->find(name); - } - - TSymbolTableLevel* getOuterLevel() { - assert(table.size() >= 2); + assert(currentLevel() >= 1); return table[currentLevel() - 1]; } - void relateToOperator(const char* name, TOperator op) { - table[0]->relateToOperator(name, op); + void relateToOperator(ESymbolLevel level, const char *name, TOperator op) + { + table[level]->relateToOperator(name, op); } - void relateToExtension(const char* name, const TString& ext) { - table[0]->relateToExtension(name, ext); + void relateToExtension(ESymbolLevel level, const char *name, const TString &ext) + { + table[level]->relateToExtension(name, ext); } void dump(TInfoSink &infoSink) const; - bool setDefaultPrecision(const TPublicType& type, TPrecision prec) { - if (!supportsPrecision(type.type)) + bool setDefaultPrecision(const TPublicType &type, TPrecision prec) + { + if (!SupportsPrecision(type.type)) return false; - if (type.size != 1 || type.matrix || type.array) + if (type.isAggregate()) return false; // Not allowed to set for aggregate types int indexOfLastElement = static_cast(precisionStack.size()) - 1; - (*precisionStack[indexOfLastElement])[type.type] = prec; // Uses map operator [], overwrites the current value + // Uses map operator [], overwrites the current value + (*precisionStack[indexOfLastElement])[type.type] = prec; return true; } - // Searches down the precisionStack for a precision qualifier for the specified TBasicType - TPrecision getDefaultPrecision(TBasicType type) { - if (!supportsPrecision(type)) - return EbpUndefined; - int level = static_cast(precisionStack.size()) - 1; - assert(level >= 0); // Just to be safe. Should not happen. - PrecisionStackLevel::iterator it; - TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this? - while (level >= 0) { - it = precisionStack[level]->find(type); - if (it != precisionStack[level]->end()) { - prec = (*it).second; - break; - } - level--; - } - return prec; - } + // Searches down the precisionStack for a precision qualifier + // for the specified TBasicType + TPrecision getDefaultPrecision(TBasicType type); -private: - int currentLevel() const { return static_cast(table.size()) - 1; } + static int nextUniqueId() + { + return ++uniqueIdCounter; + } - bool supportsPrecision(TBasicType type) { - // Only supports precision for int, float, and sampler types. - return type == EbtFloat || type == EbtInt || IsSampler(type); + private: + ESymbolLevel currentLevel() const + { + return static_cast(table.size() - 1); } - int uniqueId; // for unique identification in code generation - std::vector table; + std::vector table; typedef TMap PrecisionStackLevel; - std::vector precisionStack; + std::vector< PrecisionStackLevel *> precisionStack; + + static int uniqueIdCounter; }; #endif // _SYMBOL_TABLE_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp index 9262f7af8c..5b99fea948 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -7,9 +7,10 @@ #include "compiler/translator/TranslatorESSL.h" #include "compiler/translator/OutputESSL.h" +#include "angle_gl.h" -TranslatorESSL::TranslatorESSL(ShShaderType type, ShShaderSpec spec) - : TCompiler(type, spec) { +TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec) + : TCompiler(type, spec, SH_ESSL_OUTPUT) { } void TranslatorESSL::translate(TIntermNode* root) { @@ -20,13 +21,13 @@ void TranslatorESSL::translate(TIntermNode* root) { // Write emulated built-in functions if needed. getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( - sink, getShaderType() == SH_FRAGMENT_SHADER); + sink, getShaderType() == GL_FRAGMENT_SHADER); // Write array bounds clamping emulation if needed. getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); // Write translated shader. - TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable()); + TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion()); root->traverse(&outputESSL); } diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h index e18f3c25ec..55766822d1 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h @@ -7,11 +7,11 @@ #ifndef COMPILER_TRANSLATORESSL_H_ #define COMPILER_TRANSLATORESSL_H_ -#include "compiler/translator/ShHandle.h" +#include "compiler/translator/Compiler.h" class TranslatorESSL : public TCompiler { public: - TranslatorESSL(ShShaderType type, ShShaderSpec spec); + TranslatorESSL(sh::GLenum type, ShShaderSpec spec); protected: virtual void translate(TIntermNode* root); diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp index 6688d7f362..4b2aecab33 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -9,7 +9,7 @@ #include "compiler/translator/OutputGLSL.h" #include "compiler/translator/VersionGLSL.h" -static void writeVersion(ShShaderType type, TIntermNode* root, +static void writeVersion(sh::GLenum type, TIntermNode* root, TInfoSinkBase& sink) { TVersionGLSL versionGLSL(type); root->traverse(&versionGLSL); @@ -21,8 +21,8 @@ static void writeVersion(ShShaderType type, TIntermNode* root, } } -TranslatorGLSL::TranslatorGLSL(ShShaderType type, ShShaderSpec spec) - : TCompiler(type, spec) { +TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec) + : TCompiler(type, spec, SH_GLSL_OUTPUT) { } void TranslatorGLSL::translate(TIntermNode* root) { @@ -31,6 +31,9 @@ void TranslatorGLSL::translate(TIntermNode* root) { // Write GLSL version. writeVersion(getShaderType(), root, sink); + // Write extension behaviour as needed + writeExtensionBehavior(); + // Write emulated built-in functions if needed. getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( sink, false); @@ -39,6 +42,23 @@ void TranslatorGLSL::translate(TIntermNode* root) { getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); // Write translated shader. - TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable()); + TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion()); root->traverse(&outputGLSL); } + +void TranslatorGLSL::writeExtensionBehavior() { + TInfoSinkBase& sink = getInfoSink().obj; + const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin(); + iter != extensionBehavior.end(); ++iter) { + if (iter->second == EBhUndefined) + continue; + + // For GLSL output, we don't need to emit most extensions explicitly, + // but some we need to translate. + if (iter->first == "GL_EXT_shader_texture_lod") { + sink << "#extension GL_ARB_shader_texture_lod : " + << getBehaviorString(iter->second) << "\n"; + } + } +} diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h index 40bb3145e8..3c6c2e426a 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h @@ -7,14 +7,17 @@ #ifndef COMPILER_TRANSLATORGLSL_H_ #define COMPILER_TRANSLATORGLSL_H_ -#include "compiler/translator/ShHandle.h" +#include "compiler/translator/Compiler.h" class TranslatorGLSL : public TCompiler { public: - TranslatorGLSL(ShShaderType type, ShShaderSpec spec); + TranslatorGLSL(sh::GLenum type, ShShaderSpec spec); protected: virtual void translate(TIntermNode* root); + +private: + void writeExtensionBehavior(); }; #endif // COMPILER_TRANSLATORGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp index 3c1db011b6..52588e4626 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp @@ -9,16 +9,46 @@ #include "compiler/translator/InitializeParseContext.h" #include "compiler/translator/OutputHLSL.h" -TranslatorHLSL::TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output) - : TCompiler(type, spec), mOutputType(output) +TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) + : TCompiler(type, spec, output) { } void TranslatorHLSL::translate(TIntermNode *root) { TParseContext& parseContext = *GetGlobalParseContext(); - sh::OutputHLSL outputHLSL(parseContext, getResources(), mOutputType); + sh::OutputHLSL outputHLSL(parseContext, getResources(), getOutputType()); outputHLSL.output(); - mActiveUniforms = outputHLSL.getUniforms(); + + attributes = outputHLSL.getAttributes(); + outputVariables = outputHLSL.getOutputVariables(); + uniforms = outputHLSL.getUniforms(); + varyings = outputHLSL.getVaryings(); + interfaceBlocks = outputHLSL.getInterfaceBlocks(); + + mInterfaceBlockRegisterMap = outputHLSL.getInterfaceBlockRegisterMap(); + mUniformRegisterMap = outputHLSL.getUniformRegisterMap(); +} + +bool TranslatorHLSL::hasInterfaceBlock(const std::string &interfaceBlockName) const +{ + return (mInterfaceBlockRegisterMap.count(interfaceBlockName) > 0); +} + +unsigned int TranslatorHLSL::getInterfaceBlockRegister(const std::string &interfaceBlockName) const +{ + ASSERT(hasInterfaceBlock(interfaceBlockName)); + return mInterfaceBlockRegisterMap.find(interfaceBlockName)->second; +} + +bool TranslatorHLSL::hasUniform(const std::string &uniformName) const +{ + return (mUniformRegisterMap.count(uniformName) > 0); +} + +unsigned int TranslatorHLSL::getUniformRegister(const std::string &uniformName) const +{ + ASSERT(hasUniform(uniformName)); + return mUniformRegisterMap.find(uniformName)->second; } diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h index 6204b30cc2..598c8a7b30 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h @@ -7,21 +7,26 @@ #ifndef COMPILER_TRANSLATORHLSL_H_ #define COMPILER_TRANSLATORHLSL_H_ -#include "compiler/translator/ShHandle.h" -#include "compiler/translator/Uniform.h" - -class TranslatorHLSL : public TCompiler { -public: - TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output); +#include "compiler/translator/Compiler.h" +#include "common/shadervars.h" +class TranslatorHLSL : public TCompiler +{ + public: + TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); virtual TranslatorHLSL *getAsTranslatorHLSL() { return this; } - const sh::ActiveUniforms &getUniforms() { return mActiveUniforms; } -protected: + bool hasInterfaceBlock(const std::string &interfaceBlockName) const; + unsigned int getInterfaceBlockRegister(const std::string &interfaceBlockName) const; + + bool hasUniform(const std::string &uniformName) const; + unsigned int getUniformRegister(const std::string &uniformName) const; + + protected: virtual void translate(TIntermNode* root); - sh::ActiveUniforms mActiveUniforms; - ShShaderOutput mOutputType; + std::map mInterfaceBlockRegisterMap; + std::map mUniformRegisterMap; }; #endif // COMPILER_TRANSLATORHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Types.cpp b/src/3rdparty/angle/src/compiler/translator/Types.cpp new file mode 100644 index 0000000000..bafad0d64f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/Types.cpp @@ -0,0 +1,202 @@ +// +// Copyright (c) 2002-2014 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. +// + +#if defined(_MSC_VER) +#pragma warning(disable: 4718) +#endif + +#include "compiler/translator/Types.h" + +#include +#include + +TType::TType(const TPublicType &p) + : type(p.type), precision(p.precision), qualifier(p.qualifier), layoutQualifier(p.layoutQualifier), + primarySize(p.primarySize), secondarySize(p.secondarySize), array(p.array), arraySize(p.arraySize), + interfaceBlock(0), structure(0) +{ + if (p.userDef) + structure = p.userDef->getStruct(); +} + +bool TStructure::equals(const TStructure &other) const +{ + return (uniqueId() == other.uniqueId()); +} + +// +// Recursively generate mangled names. +// +TString TType::buildMangledName() const +{ + TString mangledName; + if (isMatrix()) + mangledName += 'm'; + else if (isVector()) + mangledName += 'v'; + + switch (type) + { + case EbtFloat: + mangledName += 'f'; + break; + case EbtInt: + mangledName += 'i'; + break; + case EbtUInt: + mangledName += 'u'; + break; + case EbtBool: + mangledName += 'b'; + break; + case EbtSampler2D: + mangledName += "s2"; + break; + case EbtSampler3D: + mangledName += "s3"; + break; + case EbtSamplerCube: + mangledName += "sC"; + break; + case EbtSampler2DArray: + mangledName += "s2a"; + break; + case EbtSamplerExternalOES: + mangledName += "sext"; + break; + case EbtSampler2DRect: + mangledName += "s2r"; + break; + case EbtISampler2D: + mangledName += "is2"; + break; + case EbtISampler3D: + mangledName += "is3"; + break; + case EbtISamplerCube: + mangledName += "isC"; + break; + case EbtISampler2DArray: + mangledName += "is2a"; + break; + case EbtUSampler2D: + mangledName += "us2"; + break; + case EbtUSampler3D: + mangledName += "us3"; + break; + case EbtUSamplerCube: + mangledName += "usC"; + break; + case EbtUSampler2DArray: + mangledName += "us2a"; + break; + case EbtSampler2DShadow: + mangledName += "s2s"; + break; + case EbtSamplerCubeShadow: + mangledName += "sCs"; + break; + case EbtSampler2DArrayShadow: + mangledName += "s2as"; + break; + case EbtStruct: + mangledName += structure->mangledName(); + break; + case EbtInterfaceBlock: + mangledName += interfaceBlock->mangledName(); + break; + default: + UNREACHABLE(); + } + + if (isMatrix()) + { + mangledName += static_cast('0' + getCols()); + mangledName += static_cast('x'); + mangledName += static_cast('0' + getRows()); + } + else + { + mangledName += static_cast('0' + getNominalSize()); + } + + if (isArray()) + { + char buf[20]; + snprintf(buf, sizeof(buf), "%d", arraySize); + mangledName += '['; + mangledName += buf; + mangledName += ']'; + } + return mangledName; +} + +size_t TType::getObjectSize() const +{ + size_t totalSize; + + if (getBasicType() == EbtStruct) + totalSize = structure->objectSize(); + else + totalSize = primarySize * secondarySize; + + if (isArray()) + { + size_t arraySize = getArraySize(); + if (arraySize > INT_MAX / totalSize) + totalSize = INT_MAX; + else + totalSize *= arraySize; + } + + return totalSize; +} + +bool TStructure::containsArrays() const +{ + for (size_t i = 0; i < mFields->size(); ++i) + { + const TType *fieldType = (*mFields)[i]->type(); + if (fieldType->isArray() || fieldType->isStructureContainingArrays()) + return true; + } + return false; +} + +TString TFieldListCollection::buildMangledName() const +{ + TString mangledName(mangledNamePrefix()); + mangledName += *mName; + for (size_t i = 0; i < mFields->size(); ++i) + { + mangledName += '-'; + mangledName += (*mFields)[i]->type()->getMangledName(); + } + return mangledName; +} + +size_t TFieldListCollection::calculateObjectSize() const +{ + size_t size = 0; + for (size_t i = 0; i < mFields->size(); ++i) + { + size_t fieldSize = (*mFields)[i]->type()->getObjectSize(); + if (fieldSize > INT_MAX - size) + size = INT_MAX; + else + size += fieldSize; + } + return size; +} + +int TStructure::calculateDeepestNesting() const +{ + int maxNesting = 0; + for (size_t i = 0; i < mFields->size(); ++i) + maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting()); + return 1 + maxNesting; +} diff --git a/src/3rdparty/angle/src/compiler/translator/Types.h b/src/3rdparty/angle/src/compiler/translator/Types.h index 119f4f29e5..bc50a4dc64 100644 --- a/src/3rdparty/angle/src/compiler/translator/Types.h +++ b/src/3rdparty/angle/src/compiler/translator/Types.h @@ -15,76 +15,191 @@ struct TPublicType; class TType; +class TSymbol; class TField { -public: + public: POOL_ALLOCATOR_NEW_DELETE(); - TField(TType* type, TString* name) : mType(type), mName(name) {} + TField(TType *type, TString *name, const TSourceLoc &line) + : mType(type), + mName(name), + mLine(line) + { + } // TODO(alokp): We should only return const type. // Fix it by tweaking grammar. - TType* type() { return mType; } - const TType* type() const { return mType; } + TType *type() + { + return mType; + } + const TType *type() const + { + return mType; + } - const TString& name() const { return *mName; } + const TString &name() const + { + return *mName; + } + const TSourceLoc &line() const + { + return mLine; + } -private: + private: DISALLOW_COPY_AND_ASSIGN(TField); - TType* mType; - TString* mName; + TType *mType; + TString *mName; + TSourceLoc mLine; }; -typedef TVector TFieldList; -inline TFieldList* NewPoolTFieldList() +typedef TVector TFieldList; +inline TFieldList *NewPoolTFieldList() { - void* memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList)); + void *memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList)); return new(memory) TFieldList; } -class TStructure +class TFieldListCollection { -public: - POOL_ALLOCATOR_NEW_DELETE(); - TStructure(TString* name, TFieldList* fields) - : mName(name), - mFields(fields), - mObjectSize(0), - mDeepestNesting(0) { + public: + const TString &name() const + { + return *mName; + } + const TFieldList &fields() const + { + return *mFields; } - const TString& name() const { return *mName; } - const TFieldList& fields() const { return *mFields; } - - const TString& mangledName() const { + const TString &mangledName() const + { if (mMangledName.empty()) mMangledName = buildMangledName(); return mMangledName; } - size_t objectSize() const { + size_t objectSize() const + { if (mObjectSize == 0) mObjectSize = calculateObjectSize(); return mObjectSize; }; - int deepestNesting() const { + + protected: + TFieldListCollection(const TString *name, TFieldList *fields) + : mName(name), + mFields(fields), + mObjectSize(0) + { + } + TString buildMangledName() const; + size_t calculateObjectSize() const; + virtual TString mangledNamePrefix() const = 0; + + const TString *mName; + TFieldList *mFields; + + mutable TString mMangledName; + mutable size_t mObjectSize; +}; + +// May also represent interface blocks +class TStructure : public TFieldListCollection +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TStructure(const TString *name, TFieldList *fields) + : TFieldListCollection(name, fields), + mDeepestNesting(0), + mUniqueId(0) + { + } + + int deepestNesting() const + { if (mDeepestNesting == 0) mDeepestNesting = calculateDeepestNesting(); return mDeepestNesting; } bool containsArrays() const; -private: + bool equals(const TStructure &other) const; + + void setUniqueId(int uniqueId) + { + mUniqueId = uniqueId; + } + + int uniqueId() const + { + ASSERT(mUniqueId != 0); + return mUniqueId; + } + + private: DISALLOW_COPY_AND_ASSIGN(TStructure); - TString buildMangledName() const; - size_t calculateObjectSize() const; + virtual TString mangledNamePrefix() const + { + return "struct-"; + } int calculateDeepestNesting() const; - TString* mName; - TFieldList* mFields; - - mutable TString mMangledName; - mutable size_t mObjectSize; mutable int mDeepestNesting; + int mUniqueId; +}; + +class TInterfaceBlock : public TFieldListCollection +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TInterfaceBlock(const TString *name, TFieldList *fields, const TString *instanceName, + int arraySize, const TLayoutQualifier &layoutQualifier) + : TFieldListCollection(name, fields), + mInstanceName(instanceName), + mArraySize(arraySize), + mBlockStorage(layoutQualifier.blockStorage), + mMatrixPacking(layoutQualifier.matrixPacking) + { + } + + const TString &instanceName() const + { + return *mInstanceName; + } + bool hasInstanceName() const + { + return mInstanceName != NULL; + } + bool isArray() const + { + return mArraySize > 0; + } + int arraySize() const + { + return mArraySize; + } + TLayoutBlockStorage blockStorage() const + { + return mBlockStorage; + } + TLayoutMatrixPacking matrixPacking() const + { + return mMatrixPacking; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TInterfaceBlock); + virtual TString mangledNamePrefix() const + { + return "iblock-"; + } + + const TString *mInstanceName; // for interface block instance names + int mArraySize; // 0 if not an array + TLayoutBlockStorage mBlockStorage; + TLayoutMatrixPacking mMatrixPacking; }; // @@ -92,123 +207,228 @@ private: // class TType { -public: + public: POOL_ALLOCATOR_NEW_DELETE(); - TType() {} - TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, unsigned char s = 1, bool m = false, bool a = false) : - type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0), structure(0) + TType() + { + } + TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1) + : type(t), precision(EbpUndefined), qualifier(EvqGlobal), + layoutQualifier(TLayoutQualifier::create()), + primarySize(ps), secondarySize(ss), array(false), arraySize(0), + interfaceBlock(0), structure(0) + { + } + TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, + unsigned char ps = 1, unsigned char ss = 1, bool a = false) + : type(t), precision(p), qualifier(q), + layoutQualifier(TLayoutQualifier::create()), + primarySize(ps), secondarySize(ss), array(a), arraySize(0), + interfaceBlock(0), structure(0) { } explicit TType(const TPublicType &p); - TType(TStructure* userDef, TPrecision p = EbpUndefined) : - type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0), structure(userDef) + TType(TStructure *userDef, TPrecision p = EbpUndefined) + : type(EbtStruct), precision(p), qualifier(EvqTemporary), + layoutQualifier(TLayoutQualifier::create()), + primarySize(1), secondarySize(1), array(false), arraySize(0), + interfaceBlock(0), structure(userDef) + { + } + TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn, + TLayoutQualifier layoutQualifierIn, int arraySizeIn) + : type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn), + layoutQualifier(layoutQualifierIn), + primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn), + interfaceBlock(interfaceBlockIn), structure(0) { } - TBasicType getBasicType() const { return type; } - void setBasicType(TBasicType t) { type = t; } + TBasicType getBasicType() const + { + return type; + } + void setBasicType(TBasicType t) + { + type = t; + } - TPrecision getPrecision() const { return precision; } - void setPrecision(TPrecision p) { precision = p; } + TPrecision getPrecision() const + { + return precision; + } + void setPrecision(TPrecision p) + { + precision = p; + } - TQualifier getQualifier() const { return qualifier; } - void setQualifier(TQualifier q) { qualifier = q; } + TQualifier getQualifier() const + { + return qualifier; + } + void setQualifier(TQualifier q) + { + qualifier = q; + } - // One-dimensional size of single instance type - int getNominalSize() const { return size; } - void setNominalSize(unsigned char s) { size = s; } - // Full size of single instance of type - size_t getObjectSize() const; + TLayoutQualifier getLayoutQualifier() const + { + return layoutQualifier; + } + void setLayoutQualifier(TLayoutQualifier lq) + { + layoutQualifier = lq; + } - int elementRegisterCount() const + int getNominalSize() const { - if (structure) - { - const TFieldList &fields = getStruct()->fields(); - int registerCount = 0; + return primarySize; + } + int getSecondarySize() const + { + return secondarySize; + } + int getCols() const + { + ASSERT(isMatrix()); + return primarySize; + } + int getRows() const + { + ASSERT(isMatrix()); + return secondarySize; + } + void setPrimarySize(unsigned char ps) + { + primarySize = ps; + } + void setSecondarySize(unsigned char ss) + { + secondarySize = ss; + } - for (size_t i = 0; i < fields.size(); i++) - { - registerCount += fields[i]->type()->totalRegisterCount(); - } + // Full size of single instance of type + size_t getObjectSize() const; - return registerCount; - } - else if (isMatrix()) - { - return getNominalSize(); - } - else - { - return 1; - } + bool isMatrix() const + { + return primarySize > 1 && secondarySize > 1; } - - int totalRegisterCount() const + bool isArray() const { - if (array) - { - return arraySize * elementRegisterCount(); - } - else - { - return elementRegisterCount(); - } + return array ? true : false; + } + int getArraySize() const + { + return arraySize; + } + void setArraySize(int s) + { + array = true; + arraySize = s; + } + void clearArrayness() + { + array = false; + arraySize = 0; } - bool isMatrix() const { return matrix ? true : false; } - void setMatrix(bool m) { matrix = m; } - - bool isArray() const { return array ? true : false; } - int getArraySize() const { return arraySize; } - void setArraySize(int s) { array = true; arraySize = s; } - void clearArrayness() { array = false; arraySize = 0; } + TInterfaceBlock *getInterfaceBlock() const + { + return interfaceBlock; + } + void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn) + { + interfaceBlock = interfaceBlockIn; + } + bool isInterfaceBlock() const + { + return type == EbtInterfaceBlock; + } - bool isVector() const { return size > 1 && !matrix; } - bool isScalar() const { return size == 1 && !matrix && !structure; } + bool isVector() const + { + return primarySize > 1 && secondarySize == 1; + } + bool isScalar() const + { + return primarySize == 1 && secondarySize == 1 && !structure; + } + bool isScalarInt() const + { + return isScalar() && (type == EbtInt || type == EbtUInt); + } - TStructure* getStruct() const { return structure; } - void setStruct(TStructure* s) { structure = s; } + TStructure *getStruct() const + { + return structure; + } + void setStruct(TStructure *s) + { + structure = s; + } - const TString& getMangledName() const { - if (mangled.empty()) { + const TString &getMangledName() + { + if (mangled.empty()) + { mangled = buildMangledName(); mangled += ';'; } + return mangled; } - bool sameElementType(const TType& right) const { - return type == right.type && - size == right.size && - matrix == right.matrix && - structure == right.structure; + bool sameElementType(const TType &right) const + { + return type == right.type && + primarySize == right.primarySize && + secondarySize == right.secondarySize && + structure == right.structure; } - bool operator==(const TType& right) const { - return type == right.type && - size == right.size && - matrix == right.matrix && - array == right.array && (!array || arraySize == right.arraySize) && - structure == right.structure; + bool operator==(const TType &right) const + { + return type == right.type && + primarySize == right.primarySize && + secondarySize == right.secondarySize && + array == right.array && (!array || arraySize == right.arraySize) && + structure == right.structure; // don't check the qualifier, it's not ever what's being sought after } - bool operator!=(const TType& right) const { + bool operator!=(const TType &right) const + { return !operator==(right); } - bool operator<(const TType& right) const { - if (type != right.type) return type < right.type; - if (size != right.size) return size < right.size; - if (matrix != right.matrix) return matrix < right.matrix; - if (array != right.array) return array < right.array; - if (arraySize != right.arraySize) return arraySize < right.arraySize; - if (structure != right.structure) return structure < right.structure; + bool operator<(const TType &right) const + { + if (type != right.type) + return type < right.type; + if (primarySize != right.primarySize) + return primarySize < right.primarySize; + if (secondarySize != right.secondarySize) + return secondarySize < right.secondarySize; + if (array != right.array) + return array < right.array; + if (arraySize != right.arraySize) + return arraySize < right.arraySize; + if (structure != right.structure) + return structure < right.structure; return false; } - const char* getBasicString() const { return ::getBasicString(type); } - const char* getPrecisionString() const { return ::getPrecisionString(precision); } - const char* getQualifierString() const { return ::getQualifierString(qualifier); } + const char *getBasicString() const + { + return ::getBasicString(type); + } + const char *getPrecisionString() const + { + return ::getPrecisionString(precision); + } + const char *getQualifierString() const + { + return ::getQualifierString(qualifier); + } TString getCompleteString() const; // If this type is a struct, returns the deepest struct nesting of @@ -223,26 +443,35 @@ public: // For type "nesting2", this method would return 2 -- the number // of structures through which indirection must occur to reach the // deepest field (nesting2.field1.position). - int getDeepestStructNesting() const { + int getDeepestStructNesting() const + { return structure ? structure->deepestNesting() : 0; } - bool isStructureContainingArrays() const { + bool isStructureContainingArrays() const + { return structure ? structure->containsArrays() : false; } -private: + protected: TString buildMangledName() const; + size_t getStructSize() const; + void computeDeepestStructNesting(); TBasicType type; TPrecision precision; TQualifier qualifier; - unsigned char size; - bool matrix; + TLayoutQualifier layoutQualifier; + unsigned char primarySize; // size of vector or cols matrix + unsigned char secondarySize; // rows of a matrix bool array; int arraySize; - TStructure* structure; // 0 unless this is a struct + // 0 unless this is an interface block, or interface block member variable + TInterfaceBlock *interfaceBlock; + + // 0 unless this is a struct + TStructure *structure; mutable TString mangled; }; @@ -259,32 +488,40 @@ private: struct TPublicType { TBasicType type; + TLayoutQualifier layoutQualifier; TQualifier qualifier; TPrecision precision; - unsigned char size; // size of vector or matrix, not size of array - bool matrix; + unsigned char primarySize; // size of vector or cols of matrix + unsigned char secondarySize; // rows of matrix bool array; int arraySize; - TType* userDef; + TType *userDef; TSourceLoc line; - void setBasic(TBasicType bt, TQualifier q, const TSourceLoc& ln) + void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln) { type = bt; + layoutQualifier = TLayoutQualifier::create(); qualifier = q; precision = EbpUndefined; - size = 1; - matrix = false; + primarySize = 1; + secondarySize = 1; array = false; arraySize = 0; userDef = 0; line = ln; } - void setAggregate(unsigned char s, bool m = false) + void setAggregate(unsigned char size) + { + primarySize = size; + } + + void setMatrix(unsigned char c, unsigned char r) { - size = s; - matrix = m; + ASSERT(c > 1 && r > 1 && c <= 4 && r <= 4); + primarySize = c; + secondarySize = r; } void setArray(bool a, int s = 0) @@ -302,6 +539,38 @@ struct TPublicType return userDef->isStructureContainingArrays(); } + + bool isMatrix() const + { + return primarySize > 1 && secondarySize > 1; + } + + bool isVector() const + { + return primarySize > 1 && secondarySize == 1; + } + + int getCols() const + { + ASSERT(isMatrix()); + return primarySize; + } + + int getRows() const + { + ASSERT(isMatrix()); + return secondarySize; + } + + int getNominalSize() const + { + return primarySize; + } + + bool isAggregate() const + { + return array || isMatrix() || isVector(); + } }; #endif // _TYPES_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp index b7826119ae..65f50c4cc3 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp @@ -12,6 +12,7 @@ #include "compiler/translator/InfoSink.h" #include "compiler/translator/OutputHLSL.h" +#include "compiler/translator/UtilsHLSL.h" namespace sh { @@ -117,7 +118,7 @@ bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node) { int i = mTemporaryIndex; - out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n"; + out << TypeString(node->getType()) << " s" << i << ";\n"; out << "{\n"; diff --git a/src/3rdparty/angle/src/compiler/translator/Uniform.cpp b/src/3rdparty/angle/src/compiler/translator/Uniform.cpp deleted file mode 100644 index 922e13f071..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/Uniform.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) 2013 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/Uniform.h" - -namespace sh -{ - -Uniform::Uniform(GLenum type, GLenum precision, const char *name, int arraySize, int registerIndex) -{ - this->type = type; - this->precision = precision; - this->name = name; - this->arraySize = arraySize; - this->registerIndex = registerIndex; -} - -} diff --git a/src/3rdparty/angle/src/compiler/translator/Uniform.h b/src/3rdparty/angle/src/compiler/translator/Uniform.h deleted file mode 100644 index 4c53ffa7d2..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/Uniform.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -#ifndef COMPILER_UNIFORM_H_ -#define COMPILER_UNIFORM_H_ - -#include -#include - -#define GL_APICALL -#include - -namespace sh -{ - -struct Uniform -{ - Uniform(GLenum type, GLenum precision, const char *name, int arraySize, int registerIndex); - - GLenum type; - GLenum precision; - std::string name; - unsigned int arraySize; - - int registerIndex; -}; - -typedef std::vector ActiveUniforms; - -} - -#endif // COMPILER_UNIFORM_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp new file mode 100644 index 0000000000..41a7d2c10b --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp @@ -0,0 +1,291 @@ +// +// Copyright (c) 2014 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. +// +// UniformHLSL.cpp: +// Methods for GLSL to HLSL translation for uniforms and interface blocks. +// + +#include "OutputHLSL.h" +#include "common/blocklayout.h" +#include "common/utilities.h" +#include "compiler/translator/UniformHLSL.h" +#include "compiler/translator/StructureHLSL.h" +#include "compiler/translator/util.h" +#include "compiler/translator/UtilsHLSL.h" + +namespace sh +{ + +static const char *UniformRegisterPrefix(const TType &type) +{ + if (IsSampler(type.getBasicType())) + { + return "s"; + } + else + { + return "c"; + } +} + +static TString InterfaceBlockFieldName(const TInterfaceBlock &interfaceBlock, const TField &field) +{ + if (interfaceBlock.hasInstanceName()) + { + return interfaceBlock.name() + "." + field.name(); + } + else + { + return field.name(); + } +} + +static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage) +{ + const TType &fieldType = *field.type(); + const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking; + ASSERT(matrixPacking != EmpUnspecified); + TStructure *structure = fieldType.getStruct(); + + if (fieldType.isMatrix()) + { + // Use HLSL row-major packing for GLSL column-major matrices + const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major"); + return matrixPackString + " " + TypeString(fieldType); + } + else if (structure) + { + // Use HLSL row-major packing for GLSL column-major matrices + return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor, + blockStorage == EbsStd140); + } + else + { + return TypeString(fieldType); + } +} + +static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock) +{ + return DecoratePrivate(interfaceBlock.name()) + "_type"; +} + +UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType) + : mUniformRegister(0), + mInterfaceBlockRegister(0), + mSamplerRegister(0), + mStructureHLSL(structureHLSL), + mOutputType(outputType) +{} + +void UniformHLSL::reserveUniformRegisters(unsigned int registerCount) +{ + mUniformRegister = registerCount; +} + +void UniformHLSL::reserveInterfaceBlockRegisters(unsigned int registerCount) +{ + mInterfaceBlockRegister = registerCount; +} + +unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name) +{ + unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister); + + GetVariableTraverser traverser(&mActiveUniforms); + traverser.traverse(type, name); + + const sh::Uniform &activeUniform = mActiveUniforms.back(); + mUniformRegisterMap[activeUniform.name] = registerIndex; + + unsigned int registerCount = HLSLVariableRegisterCount(activeUniform, mOutputType); + if (IsSampler(type.getBasicType())) + { + mSamplerRegister += registerCount; + } + else + { + mUniformRegister += registerCount; + } + + return registerIndex; +} + +TString UniformHLSL::uniformsHeader(ShShaderOutput outputType, const ReferencedSymbols &referencedUniforms) +{ + TString uniforms; + + for (ReferencedSymbols::const_iterator uniformIt = referencedUniforms.begin(); + uniformIt != referencedUniforms.end(); uniformIt++) + { + const TIntermSymbol &uniform = *uniformIt->second; + const TType &type = uniform.getType(); + const TString &name = uniform.getSymbol(); + + unsigned int registerIndex = declareUniformAndAssignRegister(type, name); + + if (outputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture + { + uniforms += "uniform " + SamplerString(type) + " sampler_" + DecorateUniform(name, type) + ArrayString(type) + + " : register(s" + str(registerIndex) + ");\n"; + + uniforms += "uniform " + TextureString(type) + " texture_" + DecorateUniform(name, type) + ArrayString(type) + + " : register(t" + str(registerIndex) + ");\n"; + } + else + { + const TStructure *structure = type.getStruct(); + const TString &typeName = (structure ? QualifiedStructNameString(*structure, false, false) : TypeString(type)); + + const TString ®isterString = TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")"; + + uniforms += "uniform " + typeName + " " + DecorateUniform(name, type) + ArrayString(type) + " : " + registerString + ";\n"; + } + } + + return (uniforms.empty() ? "" : ("// Uniforms\n\n" + uniforms)); +} + +TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks) +{ + TString interfaceBlocks; + + for (ReferencedSymbols::const_iterator interfaceBlockIt = referencedInterfaceBlocks.begin(); + interfaceBlockIt != referencedInterfaceBlocks.end(); interfaceBlockIt++) + { + const TType &nodeType = interfaceBlockIt->second->getType(); + const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock(); + const TFieldList &fieldList = interfaceBlock.fields(); + + unsigned int arraySize = static_cast(interfaceBlock.arraySize()); + unsigned int activeRegister = mInterfaceBlockRegister; + + InterfaceBlock activeBlock(interfaceBlock.name().c_str(), arraySize); + for (unsigned int typeIndex = 0; typeIndex < fieldList.size(); typeIndex++) + { + const TField &field = *fieldList[typeIndex]; + const TString &fullFieldName = InterfaceBlockFieldName(interfaceBlock, field); + + bool isRowMajor = (field.type()->getLayoutQualifier().matrixPacking == EmpRowMajor); + GetInterfaceBlockFieldTraverser traverser(&activeBlock.fields, isRowMajor); + traverser.traverse(*field.type(), fullFieldName); + } + + mInterfaceBlockRegisterMap[activeBlock.name] = activeRegister; + mInterfaceBlockRegister += std::max(1u, arraySize); + + activeBlock.layout = GetBlockLayoutType(interfaceBlock.blockStorage()); + + if (interfaceBlock.matrixPacking() == EmpRowMajor) + { + activeBlock.isRowMajorLayout = true; + } + + mActiveInterfaceBlocks.push_back(activeBlock); + + if (interfaceBlock.hasInstanceName()) + { + interfaceBlocks += interfaceBlockStructString(interfaceBlock); + } + + if (arraySize > 0) + { + for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) + { + interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex); + } + } + else + { + interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX); + } + } + + return (interfaceBlocks.empty() ? "" : ("// Interface Blocks\n\n" + interfaceBlocks)); +} + +TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex) +{ + const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : ""); + const TString &blockName = interfaceBlock.name() + arrayIndexString; + TString hlsl; + + hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n" + "{\n"; + + if (interfaceBlock.hasInstanceName()) + { + hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " + + interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n"; + } + else + { + const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); + hlsl += interfaceBlockMembersString(interfaceBlock, blockStorage); + } + + hlsl += "};\n\n"; + + return hlsl; +} + +TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex) +{ + if (!interfaceBlock.hasInstanceName()) + { + return ""; + } + else if (interfaceBlock.isArray()) + { + return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex); + } + else + { + return Decorate(interfaceBlock.instanceName()); + } +} + +TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage) +{ + TString hlsl; + + Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper(); + + for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++) + { + const TField &field = *interfaceBlock.fields()[typeIndex]; + const TType &fieldType = *field.type(); + + if (blockStorage == EbsStd140) + { + // 2 and 3 component vector types in some cases need pre-padding + hlsl += padHelper.prePadding(fieldType); + } + + hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage) + + " " + Decorate(field.name()) + ArrayString(fieldType) + ";\n"; + + // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff + if (blockStorage == EbsStd140) + { + const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor); + hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking); + } + } + + return hlsl; +} + +TString UniformHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock) +{ + const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); + + return "struct " + InterfaceBlockStructName(interfaceBlock) + "\n" + "{\n" + + interfaceBlockMembersString(interfaceBlock, blockStorage) + + "};\n\n"; +} + +} diff --git a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h new file mode 100644 index 0000000000..835b1ef2c8 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h @@ -0,0 +1,66 @@ +// +// Copyright (c) 2014 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. +// +// UniformHLSL.h: +// Methods for GLSL to HLSL translation for uniforms and interface blocks. +// + +#ifndef TRANSLATOR_UNIFORMHLSL_H_ +#define TRANSLATOR_UNIFORMHLSL_H_ + +#include "common/shadervars.h" +#include "compiler/translator/Types.h" + +namespace sh +{ +class StructureHLSL; + +class UniformHLSL +{ + public: + UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType); + + void reserveUniformRegisters(unsigned int registerCount); + void reserveInterfaceBlockRegisters(unsigned int registerCount); + TString uniformsHeader(ShShaderOutput outputType, const ReferencedSymbols &referencedUniforms); + TString interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks); + + // Used for direct index references + static TString interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex); + + const std::vector &getUniforms() const { return mActiveUniforms; } + const std::vector &getInterfaceBlocks() const { return mActiveInterfaceBlocks; } + const std::map &getInterfaceBlockRegisterMap() const + { + return mInterfaceBlockRegisterMap; + } + const std::map &getUniformRegisterMap() const + { + return mUniformRegisterMap; + } + + private: + TString interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex); + TString interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage); + TString interfaceBlockStructString(const TInterfaceBlock &interfaceBlock); + + // Returns the uniform's register index + unsigned int declareUniformAndAssignRegister(const TType &type, const TString &name); + + unsigned int mUniformRegister; + unsigned int mInterfaceBlockRegister; + unsigned int mSamplerRegister; + StructureHLSL *mStructureHLSL; + ShShaderOutput mOutputType; + + std::vector mActiveUniforms; + std::vector mActiveInterfaceBlocks; + std::map mInterfaceBlockRegisterMap; + std::map mUniformRegisterMap; +}; + +} + +#endif // TRANSLATOR_UNIFORMHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp new file mode 100644 index 0000000000..de0c36ca65 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp @@ -0,0 +1,243 @@ +// +// Copyright (c) 2014 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. +// +// UtilsHLSL.cpp: +// Utility methods for GLSL to HLSL translation. +// + +#include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/StructureHLSL.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +TString SamplerString(const TType &type) +{ + if (IsShadowSampler(type.getBasicType())) + { + return "SamplerComparisonState"; + } + else + { + return "SamplerState"; + } +} + +TString TextureString(const TType &type) +{ + switch (type.getBasicType()) + { + case EbtSampler2D: return "Texture2D"; + case EbtSamplerCube: return "TextureCube"; + case EbtSamplerExternalOES: return "Texture2D"; + case EbtSampler2DArray: return "Texture2DArray"; + case EbtSampler3D: return "Texture3D"; + case EbtISampler2D: return "Texture2D"; + case EbtISampler3D: return "Texture3D"; + case EbtISamplerCube: return "Texture2DArray"; + case EbtISampler2DArray: return "Texture2DArray"; + case EbtUSampler2D: return "Texture2D"; + case EbtUSampler3D: return "Texture3D"; + case EbtUSamplerCube: return "Texture2DArray"; + case EbtUSampler2DArray: return "Texture2DArray"; + case EbtSampler2DShadow: return "Texture2D"; + case EbtSamplerCubeShadow: return "TextureCube"; + case EbtSampler2DArrayShadow: return "Texture2DArray"; + default: UNREACHABLE(); + } + + return ""; +} + +TString DecorateUniform(const TString &string, const TType &type) +{ + if (type.getBasicType() == EbtSamplerExternalOES) + { + return "ex_" + string; + } + + return Decorate(string); +} + +TString DecorateField(const TString &string, const TStructure &structure) +{ + if (structure.name().compare(0, 3, "gl_") != 0) + { + return Decorate(string); + } + + return string; +} + +TString DecoratePrivate(const TString &privateText) +{ + return "dx_" + privateText; +} + +TString Decorate(const TString &string) +{ + if (string.compare(0, 3, "gl_") != 0) + { + return "_" + string; + } + + return string; +} + +TString TypeString(const TType &type) +{ + const TStructure* structure = type.getStruct(); + if (structure) + { + const TString& typeName = structure->name(); + if (typeName != "") + { + return StructNameString(*structure); + } + else // Nameless structure, define in place + { + return StructureHLSL::defineNameless(*structure); + } + } + else if (type.isMatrix()) + { + int cols = type.getCols(); + int rows = type.getRows(); + return "float" + str(cols) + "x" + str(rows); + } + else + { + switch (type.getBasicType()) + { + case EbtFloat: + switch (type.getNominalSize()) + { + case 1: return "float"; + case 2: return "float2"; + case 3: return "float3"; + case 4: return "float4"; + } + case EbtInt: + switch (type.getNominalSize()) + { + case 1: return "int"; + case 2: return "int2"; + case 3: return "int3"; + case 4: return "int4"; + } + case EbtUInt: + switch (type.getNominalSize()) + { + case 1: return "uint"; + case 2: return "uint2"; + case 3: return "uint3"; + case 4: return "uint4"; + } + case EbtBool: + switch (type.getNominalSize()) + { + case 1: return "bool"; + case 2: return "bool2"; + case 3: return "bool3"; + case 4: return "bool4"; + } + case EbtVoid: + return "void"; + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + return "sampler2D"; + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + return "samplerCUBE"; + case EbtSamplerExternalOES: + return "sampler2D"; + default: + break; + } + } + + UNREACHABLE(); + return ""; +} + +TString StructNameString(const TStructure &structure) +{ + if (structure.name().empty()) + { + return ""; + } + + return "ss" + str(structure.uniqueId()) + "_" + structure.name(); +} + +TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMajorPacking, + bool useStd140Packing) +{ + if (structure.name() == "") + { + return ""; + } + + TString prefix = ""; + + // Structs packed with row-major matrices in HLSL are prefixed with "rm" + // GLSL column-major maps to HLSL row-major, and the converse is true + + if (useStd140Packing) + { + prefix += "std_"; + } + + if (useHLSLRowMajorPacking) + { + prefix += "rm_"; + } + + return prefix + StructNameString(structure); +} + +TString InterpolationString(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqVaryingIn: return ""; + case EvqFragmentIn: return ""; + case EvqInvariantVaryingIn: return ""; + case EvqSmoothIn: return "linear"; + case EvqFlatIn: return "nointerpolation"; + case EvqCentroidIn: return "centroid"; + case EvqVaryingOut: return ""; + case EvqVertexOut: return ""; + case EvqInvariantVaryingOut: return ""; + case EvqSmoothOut: return "linear"; + case EvqFlatOut: return "nointerpolation"; + case EvqCentroidOut: return "centroid"; + default: UNREACHABLE(); + } + + return ""; +} + +TString QualifierString(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqIn: return "in"; + case EvqOut: return "inout"; // 'out' results in an HLSL error if not all fields are written, for GLSL it's undefined + case EvqInOut: return "inout"; + case EvqConstReadOnly: return "const"; + default: UNREACHABLE(); + } + + return ""; +} + +} diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h new file mode 100644 index 0000000000..aaa3ddf5d2 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2014 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. +// +// UtilsHLSL.h: +// Utility methods for GLSL to HLSL translation. +// + +#ifndef TRANSLATOR_UTILSHLSL_H_ +#define TRANSLATOR_UTILSHLSL_H_ + +#include +#include "compiler/translator/Types.h" + +#include "angle_gl.h" + +namespace sh +{ + +TString TextureString(const TType &type); +TString SamplerString(const TType &type); +// Prepends an underscore to avoid naming clashes +TString Decorate(const TString &string); +TString DecorateUniform(const TString &string, const TType &type); +TString DecorateField(const TString &string, const TStructure &structure); +TString DecoratePrivate(const TString &privateText); +TString TypeString(const TType &type); +TString StructNameString(const TStructure &structure); +TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMajorPacking, + bool useStd140Packing); +TString InterpolationString(TQualifier qualifier); +TString QualifierString(TQualifier qualifier); + +} + +#endif // TRANSLATOR_UTILSHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp index 3c2cc41cda..c1a7b7524f 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -8,26 +8,10 @@ #include "compiler/translator/InfoSink.h" #include "compiler/translator/InitializeParseContext.h" #include "compiler/translator/ParseContext.h" +#include "angle_gl.h" -namespace { -bool IsLoopIndex(const TIntermSymbol* symbol, const TLoopStack& stack) { - for (TLoopStack::const_iterator i = stack.begin(); i != stack.end(); ++i) { - if (i->index.id == symbol->getId()) - return true; - } - return false; -} - -void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) { - for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) { - if (i->index.id == symbol->getId()) { - ASSERT(i->loop != NULL); - i->loop->setUnrollFlag(true); - return; - } - } - UNREACHABLE(); -} +namespace +{ // Traverses a node to check if it represents a constant index expression. // Definition: @@ -38,110 +22,146 @@ void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) { // - Constant expressions // - Loop indices as defined in section 4 // - Expressions composed of both of the above -class ValidateConstIndexExpr : public TIntermTraverser { -public: - ValidateConstIndexExpr(const TLoopStack& stack) +class ValidateConstIndexExpr : public TIntermTraverser +{ + public: + ValidateConstIndexExpr(TLoopStack& stack) : mValid(true), mLoopStack(stack) {} // Returns true if the parsed node represents a constant index expression. bool isValid() const { return mValid; } - virtual void visitSymbol(TIntermSymbol* symbol) { + virtual void visitSymbol(TIntermSymbol *symbol) + { // Only constants and loop indices are allowed in a // constant index expression. - if (mValid) { + if (mValid) + { mValid = (symbol->getQualifier() == EvqConst) || - IsLoopIndex(symbol, mLoopStack); + (mLoopStack.findLoop(symbol)); } } -private: + private: bool mValid; - const TLoopStack& mLoopStack; + TLoopStack& mLoopStack; }; -// Traverses a node to check if it uses a loop index. -// If an int loop index is used in its body as a sampler array index, -// mark the loop for unroll. -class ValidateLoopIndexExpr : public TIntermTraverser { -public: - ValidateLoopIndexExpr(TLoopStack& stack) - : mUsesFloatLoopIndex(false), - mUsesIntLoopIndex(false), - mLoopStack(stack) {} - - bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; } - bool usesIntLoopIndex() const { return mUsesIntLoopIndex; } - - virtual void visitSymbol(TIntermSymbol* symbol) { - if (IsLoopIndex(symbol, mLoopStack)) { - switch (symbol->getBasicType()) { - case EbtFloat: - mUsesFloatLoopIndex = true; - break; - case EbtInt: - mUsesIntLoopIndex = true; - MarkLoopForUnroll(symbol, mLoopStack); - break; - default: - UNREACHABLE(); - } - } +const char *GetOperatorString(TOperator op) +{ + switch (op) + { + case EOpInitialize: return "="; + case EOpAssign: return "="; + case EOpAddAssign: return "+="; + case EOpSubAssign: return "-="; + case EOpDivAssign: return "/="; + + // Fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: return "*="; + + // Fall-through. + case EOpIndexDirect: + case EOpIndexIndirect: return "[]"; + + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: return "."; + case EOpVectorSwizzle: return "."; + case EOpAdd: return "+"; + case EOpSub: return "-"; + case EOpMul: return "*"; + case EOpDiv: return "/"; + case EOpMod: UNIMPLEMENTED(); break; + case EOpEqual: return "=="; + case EOpNotEqual: return "!="; + case EOpLessThan: return "<"; + case EOpGreaterThan: return ">"; + case EOpLessThanEqual: return "<="; + case EOpGreaterThanEqual: return ">="; + + // Fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: return "*"; + + case EOpLogicalOr: return "||"; + case EOpLogicalXor: return "^^"; + case EOpLogicalAnd: return "&&"; + case EOpNegative: return "-"; + case EOpVectorLogicalNot: return "not"; + case EOpLogicalNot: return "!"; + case EOpPostIncrement: return "++"; + case EOpPostDecrement: return "--"; + case EOpPreIncrement: return "++"; + case EOpPreDecrement: return "--"; + + case EOpRadians: return "radians"; + case EOpDegrees: return "degrees"; + case EOpSin: return "sin"; + case EOpCos: return "cos"; + case EOpTan: return "tan"; + case EOpAsin: return "asin"; + case EOpAcos: return "acos"; + case EOpAtan: return "atan"; + case EOpExp: return "exp"; + case EOpLog: return "log"; + case EOpExp2: return "exp2"; + case EOpLog2: return "log2"; + case EOpSqrt: return "sqrt"; + case EOpInverseSqrt: return "inversesqrt"; + case EOpAbs: return "abs"; + case EOpSign: return "sign"; + case EOpFloor: return "floor"; + case EOpCeil: return "ceil"; + case EOpFract: return "fract"; + case EOpLength: return "length"; + case EOpNormalize: return "normalize"; + case EOpDFdx: return "dFdx"; + case EOpDFdy: return "dFdy"; + case EOpFwidth: return "fwidth"; + case EOpAny: return "any"; + case EOpAll: return "all"; + + default: break; } + return ""; +} -private: - bool mUsesFloatLoopIndex; - bool mUsesIntLoopIndex; - TLoopStack& mLoopStack; -}; -} // namespace +} // namespace anonymous -ValidateLimitations::ValidateLimitations(ShShaderType shaderType, - TInfoSinkBase& sink) +ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, + TInfoSinkBase &sink) : mShaderType(shaderType), mSink(sink), mNumErrors(0) { } -bool ValidateLimitations::visitBinary(Visit, TIntermBinary* node) +bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node) { // Check if loop index is modified in the loop body. validateOperation(node, node->getLeft()); // Check indexing. - switch (node->getOp()) { + switch (node->getOp()) + { case EOpIndexDirect: - validateIndexing(node); - break; case EOpIndexIndirect: -#if defined(__APPLE__) - // Loop unrolling is a work-around for a Mac Cg compiler bug where it - // crashes when a sampler array's index is also the loop index. - // Once Apple fixes this bug, we should remove the code in this CL. - // See http://codereview.appspot.com/4331048/. - if ((node->getLeft() != NULL) && (node->getRight() != NULL) && - (node->getLeft()->getAsSymbolNode())) { - TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode(); - if (IsSampler(symbol->getBasicType()) && symbol->isArray()) { - ValidateLoopIndexExpr validate(mLoopStack); - node->getRight()->traverse(&validate); - if (validate.usesFloatLoopIndex()) { - error(node->getLine(), - "sampler array index is float loop index", - "for"); - } - } - } -#endif validateIndexing(node); break; - default: break; + default: + break; } return true; } -bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node) +bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node) { // Check if loop index is modified in the loop body. validateOperation(node, node->getOperand()); @@ -149,7 +169,7 @@ bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node) return true; } -bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node) +bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node) { switch (node->getOp()) { case EOpFunctionCall: @@ -161,22 +181,20 @@ bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node) return true; } -bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node) +bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node) { if (!validateLoopType(node)) return false; - TLoopInfo info; - memset(&info, 0, sizeof(TLoopInfo)); - info.loop = node; - if (!validateForLoopHeader(node, &info)) + if (!validateForLoopHeader(node)) return false; - TIntermNode* body = node->getBody(); - if (body != NULL) { - mLoopStack.push_back(info); + TIntermNode *body = node->getBody(); + if (body != NULL) + { + mLoopStack.push(node); body->traverse(this); - mLoopStack.pop_back(); + mLoopStack.pop(); } // The loop is fully processed - no need to visit children. @@ -184,7 +202,7 @@ bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node) } void ValidateLimitations::error(TSourceLoc loc, - const char *reason, const char* token) + const char *reason, const char *token) { mSink.prefix(EPrefixError); mSink.location(loc); @@ -197,12 +215,13 @@ bool ValidateLimitations::withinLoopBody() const return !mLoopStack.empty(); } -bool ValidateLimitations::isLoopIndex(const TIntermSymbol* symbol) const +bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol) { - return IsLoopIndex(symbol, mLoopStack); + return mLoopStack.findLoop(symbol) != NULL; } -bool ValidateLimitations::validateLoopType(TIntermLoop* node) { +bool ValidateLimitations::validateLoopType(TIntermLoop *node) +{ TLoopType type = node->getType(); if (type == ELoopFor) return true; @@ -214,8 +233,7 @@ bool ValidateLimitations::validateLoopType(TIntermLoop* node) { return false; } -bool ValidateLimitations::validateForLoopHeader(TIntermLoop* node, - TLoopInfo* info) +bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node) { ASSERT(node->getType() == ELoopFor); @@ -223,74 +241,80 @@ bool ValidateLimitations::validateForLoopHeader(TIntermLoop* node, // The for statement has the form: // for ( init-declaration ; condition ; expression ) statement // - if (!validateForLoopInit(node, info)) + int indexSymbolId = validateForLoopInit(node); + if (indexSymbolId < 0) return false; - if (!validateForLoopCond(node, info)) + if (!validateForLoopCond(node, indexSymbolId)) return false; - if (!validateForLoopExpr(node, info)) + if (!validateForLoopExpr(node, indexSymbolId)) return false; return true; } -bool ValidateLimitations::validateForLoopInit(TIntermLoop* node, - TLoopInfo* info) +int ValidateLimitations::validateForLoopInit(TIntermLoop *node) { - TIntermNode* init = node->getInit(); - if (init == NULL) { + TIntermNode *init = node->getInit(); + if (init == NULL) + { error(node->getLine(), "Missing init declaration", "for"); - return false; + return -1; } // // init-declaration has the form: // type-specifier identifier = constant-expression // - TIntermAggregate* decl = init->getAsAggregate(); - if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) { + TIntermAggregate *decl = init->getAsAggregate(); + if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) + { error(init->getLine(), "Invalid init declaration", "for"); - return false; + return -1; } // To keep things simple do not allow declaration list. - TIntermSequence& declSeq = decl->getSequence(); - if (declSeq.size() != 1) { + TIntermSequence *declSeq = decl->getSequence(); + if (declSeq->size() != 1) + { error(decl->getLine(), "Invalid init declaration", "for"); - return false; + return -1; } - TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); - if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) { + TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode(); + if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) + { error(decl->getLine(), "Invalid init declaration", "for"); - return false; + return -1; } - TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); - if (symbol == NULL) { + TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); + if (symbol == NULL) + { error(declInit->getLine(), "Invalid init declaration", "for"); - return false; + return -1; } // The loop index has type int or float. TBasicType type = symbol->getBasicType(); - if ((type != EbtInt) && (type != EbtFloat)) { + if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) { error(symbol->getLine(), "Invalid type for loop index", getBasicString(type)); - return false; + return -1; } // The loop index is initialized with constant expression. - if (!isConstExpr(declInit->getRight())) { + if (!isConstExpr(declInit->getRight())) + { error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression", symbol->getSymbol().c_str()); - return false; + return -1; } - info->index.id = symbol->getId(); - return true; + return symbol->getId(); } -bool ValidateLimitations::validateForLoopCond(TIntermLoop* node, - TLoopInfo* info) +bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, + int indexSymbolId) { - TIntermNode* cond = node->getCondition(); - if (cond == NULL) { + TIntermNode *cond = node->getCondition(); + if (cond == NULL) + { error(node->getLine(), "Missing condition", "for"); return false; } @@ -298,24 +322,28 @@ bool ValidateLimitations::validateForLoopCond(TIntermLoop* node, // condition has the form: // loop_index relational_operator constant_expression // - TIntermBinary* binOp = cond->getAsBinaryNode(); - if (binOp == NULL) { + TIntermBinary *binOp = cond->getAsBinaryNode(); + if (binOp == NULL) + { error(node->getLine(), "Invalid condition", "for"); return false; } // Loop index should be to the left of relational operator. - TIntermSymbol* symbol = binOp->getLeft()->getAsSymbolNode(); - if (symbol == NULL) { + TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode(); + if (symbol == NULL) + { error(binOp->getLine(), "Invalid condition", "for"); return false; } - if (symbol->getId() != info->index.id) { + if (symbol->getId() != indexSymbolId) + { error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str()); return false; } // Relational operator is one of: > >= < <= == or !=. - switch (binOp->getOp()) { + switch (binOp->getOp()) + { case EOpEqual: case EOpNotEqual: case EOpLessThan: @@ -326,11 +354,12 @@ bool ValidateLimitations::validateForLoopCond(TIntermLoop* node, default: error(binOp->getLine(), "Invalid relational operator", - getOperatorString(binOp->getOp())); + GetOperatorString(binOp->getOp())); break; } // Loop index must be compared with a constant. - if (!isConstExpr(binOp->getRight())) { + if (!isConstExpr(binOp->getRight())) + { error(binOp->getLine(), "Loop index cannot be compared with non-constant expression", symbol->getSymbol().c_str()); @@ -340,11 +369,12 @@ bool ValidateLimitations::validateForLoopCond(TIntermLoop* node, return true; } -bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node, - TLoopInfo* info) +bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, + int indexSymbolId) { - TIntermNode* expr = node->getExpression(); - if (expr == NULL) { + TIntermNode *expr = node->getExpression(); + if (expr == NULL) + { error(node->getLine(), "Missing expression", "for"); return false; } @@ -358,50 +388,58 @@ bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node, // --loop_index // The last two forms are not specified in the spec, but I am assuming // its an oversight. - TIntermUnary* unOp = expr->getAsUnaryNode(); - TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode(); + TIntermUnary *unOp = expr->getAsUnaryNode(); + TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode(); TOperator op = EOpNull; - TIntermSymbol* symbol = NULL; - if (unOp != NULL) { + TIntermSymbol *symbol = NULL; + if (unOp != NULL) + { op = unOp->getOp(); symbol = unOp->getOperand()->getAsSymbolNode(); - } else if (binOp != NULL) { + } + else if (binOp != NULL) + { op = binOp->getOp(); symbol = binOp->getLeft()->getAsSymbolNode(); } // The operand must be loop index. - if (symbol == NULL) { + if (symbol == NULL) + { error(expr->getLine(), "Invalid expression", "for"); return false; } - if (symbol->getId() != info->index.id) { + if (symbol->getId() != indexSymbolId) + { error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str()); return false; } // The operator is one of: ++ -- += -=. - switch (op) { - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - ASSERT((unOp != NULL) && (binOp == NULL)); - break; - case EOpAddAssign: - case EOpSubAssign: - ASSERT((unOp == NULL) && (binOp != NULL)); - break; - default: - error(expr->getLine(), "Invalid operator", getOperatorString(op)); - return false; + switch (op) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + ASSERT((unOp != NULL) && (binOp == NULL)); + break; + case EOpAddAssign: + case EOpSubAssign: + ASSERT((unOp == NULL) && (binOp != NULL)); + break; + default: + error(expr->getLine(), "Invalid operator", GetOperatorString(op)); + return false; } // Loop index must be incremented/decremented with a constant. - if (binOp != NULL) { - if (!isConstExpr(binOp->getRight())) { + if (binOp != NULL) + { + if (!isConstExpr(binOp->getRight())) + { error(binOp->getLine(), "Loop index cannot be modified by non-constant expression", symbol->getSymbol().c_str()); @@ -412,7 +450,7 @@ bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node, return true; } -bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node) +bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node) { ASSERT(node->getOp() == EOpFunctionCall); @@ -423,9 +461,10 @@ bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node) // List of param indices for which loop indices are used as argument. typedef std::vector ParamIndex; ParamIndex pIndex; - TIntermSequence& params = node->getSequence(); - for (TIntermSequence::size_type i = 0; i < params.size(); ++i) { - TIntermSymbol* symbol = params[i]->getAsSymbolNode(); + TIntermSequence *params = node->getSequence(); + for (TIntermSequence::size_type i = 0; i < params->size(); ++i) + { + TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode(); if (symbol && isLoopIndex(symbol)) pIndex.push_back(i); } @@ -436,17 +475,19 @@ bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node) bool valid = true; TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable; - TSymbol* symbol = symbolTable.find(node->getName()); + TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion); ASSERT(symbol && symbol->isFunction()); - TFunction* function = static_cast(symbol); + TFunction *function = static_cast(symbol); for (ParamIndex::const_iterator i = pIndex.begin(); - i != pIndex.end(); ++i) { - const TParameter& param = function->getParam(*i); + i != pIndex.end(); ++i) + { + const TParameter ¶m = function->getParam(*i); TQualifier qual = param.type->getQualifier(); - if ((qual == EvqOut) || (qual == EvqInOut)) { - error(params[*i]->getLine(), + if ((qual == EvqOut) || (qual == EvqInOut)) + { + error((*params)[*i]->getLine(), "Loop index cannot be used as argument to a function out or inout parameter", - params[*i]->getAsSymbolNode()->getSymbol().c_str()); + (*params)[*i]->getAsSymbolNode()->getSymbol().c_str()); valid = false; } } @@ -454,14 +495,16 @@ bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node) return valid; } -bool ValidateLimitations::validateOperation(TIntermOperator* node, - TIntermNode* operand) { +bool ValidateLimitations::validateOperation(TIntermOperator *node, + TIntermNode* operand) +{ // Check if loop index is modified in the loop body. if (!withinLoopBody() || !node->isAssignment()) return true; - const TIntermSymbol* symbol = operand->getAsSymbolNode(); - if (symbol && isLoopIndex(symbol)) { + TIntermSymbol *symbol = operand->getAsSymbolNode(); + if (symbol && isLoopIndex(symbol)) + { error(node->getLine(), "Loop index cannot be statically assigned to within the body of the loop", symbol->getSymbol().c_str()); @@ -469,13 +512,13 @@ bool ValidateLimitations::validateOperation(TIntermOperator* node, return true; } -bool ValidateLimitations::isConstExpr(TIntermNode* node) +bool ValidateLimitations::isConstExpr(TIntermNode *node) { ASSERT(node != NULL); return node->getAsConstantUnion() != NULL; } -bool ValidateLimitations::isConstIndexExpr(TIntermNode* node) +bool ValidateLimitations::isConstIndexExpr(TIntermNode *node) { ASSERT(node != NULL); @@ -484,15 +527,15 @@ bool ValidateLimitations::isConstIndexExpr(TIntermNode* node) return validate.isValid(); } -bool ValidateLimitations::validateIndexing(TIntermBinary* node) +bool ValidateLimitations::validateIndexing(TIntermBinary *node) { ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect)); bool valid = true; - TIntermTyped* index = node->getRight(); + TIntermTyped *index = node->getRight(); // The index expression must have integral type. - if (!index->isScalar() || (index->getBasicType() != EbtInt)) { + if (!index->isScalarInt()) { error(index->getLine(), "Index expression must have integral type", index->getCompleteString().c_str()); @@ -500,10 +543,11 @@ bool ValidateLimitations::validateIndexing(TIntermBinary* node) } // The index expession must be a constant-index-expression unless // the operand is a uniform in a vertex shader. - TIntermTyped* operand = node->getLeft(); - bool skip = (mShaderType == SH_VERTEX_SHADER) && + TIntermTyped *operand = node->getLeft(); + bool skip = (mShaderType == GL_VERTEX_SHADER) && (operand->getQualifier() == EvqUniform); - if (!skip && !isConstIndexExpr(index)) { + if (!skip && !isConstIndexExpr(index)) + { error(index->getLine(), "Index expression must be constant", "[]"); valid = false; } diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h index 8839dd8b8a..8c9ebf53ed 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h +++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h @@ -4,55 +4,51 @@ // found in the LICENSE file. // -#include "GLSLANG/ShaderLang.h" #include "compiler/translator/intermediate.h" +#include "compiler/translator/LoopInfo.h" class TInfoSinkBase; -struct TLoopInfo { - struct TIndex { - int id; // symbol id. - } index; - TIntermLoop* loop; -}; -typedef TVector TLoopStack; - // Traverses intermediate tree to ensure that the shader does not exceed the // minimum functionality mandated in GLSL 1.0 spec, Appendix A. -class ValidateLimitations : public TIntermTraverser { -public: - ValidateLimitations(ShShaderType shaderType, TInfoSinkBase& sink); +class ValidateLimitations : public TIntermTraverser +{ + public: + ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase &sink); int numErrors() const { return mNumErrors; } - virtual bool visitBinary(Visit, TIntermBinary*); - virtual bool visitUnary(Visit, TIntermUnary*); - virtual bool visitAggregate(Visit, TIntermAggregate*); - virtual bool visitLoop(Visit, TIntermLoop*); + virtual bool visitBinary(Visit, TIntermBinary *); + virtual bool visitUnary(Visit, TIntermUnary *); + virtual bool visitAggregate(Visit, TIntermAggregate *); + virtual bool visitLoop(Visit, TIntermLoop *); -private: - void error(TSourceLoc loc, const char *reason, const char* token); + private: + void error(TSourceLoc loc, const char *reason, const char *token); bool withinLoopBody() const; - bool isLoopIndex(const TIntermSymbol* symbol) const; - bool validateLoopType(TIntermLoop* node); - bool validateForLoopHeader(TIntermLoop* node, TLoopInfo* info); - bool validateForLoopInit(TIntermLoop* node, TLoopInfo* info); - bool validateForLoopCond(TIntermLoop* node, TLoopInfo* info); - bool validateForLoopExpr(TIntermLoop* node, TLoopInfo* info); + bool isLoopIndex(TIntermSymbol *symbol); + bool validateLoopType(TIntermLoop *node); + + bool validateForLoopHeader(TIntermLoop *node); + // If valid, return the index symbol id; Otherwise, return -1. + int validateForLoopInit(TIntermLoop *node); + bool validateForLoopCond(TIntermLoop *node, int indexSymbolId); + bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId); + // Returns true if none of the loop indices is used as the argument to // the given function out or inout parameter. - bool validateFunctionCall(TIntermAggregate* node); - bool validateOperation(TIntermOperator* node, TIntermNode* operand); + bool validateFunctionCall(TIntermAggregate *node); + bool validateOperation(TIntermOperator *node, TIntermNode *operand); // Returns true if indexing does not exceed the minimum functionality // mandated in GLSL 1.0 spec, Appendix A, Section 5. - bool isConstExpr(TIntermNode* node); - bool isConstIndexExpr(TIntermNode* node); - bool validateIndexing(TIntermBinary* node); + bool isConstExpr(TIntermNode *node); + bool isConstIndexExpr(TIntermNode *node); + bool validateIndexing(TIntermBinary *node); - ShShaderType mShaderType; - TInfoSinkBase& mSink; + sh::GLenum mShaderType; + TInfoSinkBase &mSink; int mNumErrors; TLoopStack mLoopStack; }; diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp new file mode 100644 index 0000000000..ac1c10d6b0 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2013 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/ValidateOutputs.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/InitializeParseContext.h" +#include "compiler/translator/ParseContext.h" + +ValidateOutputs::ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers) + : mSink(sink), + mMaxDrawBuffers(maxDrawBuffers), + mNumErrors(0), + mHasUnspecifiedOutputLocation(false) +{ +} + +void ValidateOutputs::visitSymbol(TIntermSymbol *symbol) +{ + TString name = symbol->getSymbol(); + TQualifier qualifier = symbol->getQualifier(); + + if (mVisitedSymbols.count(name) == 1) + return; + + mVisitedSymbols.insert(name); + + if (qualifier == EvqFragmentOut) + { + const TType &type = symbol->getType(); + const int location = type.getLayoutQualifier().location; + + if (mHasUnspecifiedOutputLocation) + { + error(symbol->getLine(), "must explicitly specify all locations when using multiple fragment outputs", name.c_str()); + } + else if (location == -1) + { + mHasUnspecifiedOutputLocation = true; + } + else + { + OutputMap::iterator mapEntry = mOutputMap.find(location); + if (mapEntry == mOutputMap.end()) + { + const int elementCount = type.isArray() ? type.getArraySize() : 1; + if (location + elementCount > mMaxDrawBuffers) + { + error(symbol->getLine(), "output location must be < MAX_DRAW_BUFFERS", name.c_str()); + } + + for (int elementIndex = 0; elementIndex < elementCount; elementIndex++) + { + const int offsetLocation = location + elementIndex; + mOutputMap[offsetLocation] = symbol; + } + } + else + { + std::stringstream strstr; + strstr << "conflicting output locations with previously defined output '" + << mapEntry->second->getSymbol() << "'"; + + error(symbol->getLine(), strstr.str().c_str(), name.c_str()); + } + } + } +} + +void ValidateOutputs::error(TSourceLoc loc, const char *reason, const char* token) +{ + mSink.prefix(EPrefixError); + mSink.location(loc); + mSink << "'" << token << "' : " << reason << "\n"; + mNumErrors++; +} diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h new file mode 100644 index 0000000000..e391ad9486 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2013 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/intermediate.h" + +#include + +class TInfoSinkBase; + +class ValidateOutputs : public TIntermTraverser +{ + public: + ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers); + + int numErrors() const { return mNumErrors; } + + virtual void visitSymbol(TIntermSymbol*); + + private: + TInfoSinkBase& mSink; + int mMaxDrawBuffers; + int mNumErrors; + bool mHasUnspecifiedOutputLocation; + + typedef std::map OutputMap; + OutputMap mOutputMap; + std::set mVisitedSymbols; + + void error(TSourceLoc loc, const char *reason, const char* token); +}; diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp index ef888aff11..153455c4f1 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp @@ -1,196 +1,115 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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 "angle_gl.h" #include "compiler/translator/VariableInfo.h" +#include "compiler/translator/util.h" +#include "common/utilities.h" -namespace { - -TString arrayBrackets(int index) -{ - TStringStream stream; - stream << "[" << index << "]"; - return stream.str(); -} - -// Returns the data type for an attribute, uniform, or varying. -ShDataType getVariableDataType(const TType& type) -{ - switch (type.getBasicType()) { - case EbtFloat: - if (type.isMatrix()) { - switch (type.getNominalSize()) { - case 2: return SH_FLOAT_MAT2; - case 3: return SH_FLOAT_MAT3; - case 4: return SH_FLOAT_MAT4; - default: UNREACHABLE(); - } - } else if (type.isVector()) { - switch (type.getNominalSize()) { - case 2: return SH_FLOAT_VEC2; - case 3: return SH_FLOAT_VEC3; - case 4: return SH_FLOAT_VEC4; - default: UNREACHABLE(); - } - } else { - return SH_FLOAT; - } - case EbtInt: - if (type.isMatrix()) { - UNREACHABLE(); - } else if (type.isVector()) { - switch (type.getNominalSize()) { - case 2: return SH_INT_VEC2; - case 3: return SH_INT_VEC3; - case 4: return SH_INT_VEC4; - default: UNREACHABLE(); - } - } else { - return SH_INT; - } - case EbtBool: - if (type.isMatrix()) { - UNREACHABLE(); - } else if (type.isVector()) { - switch (type.getNominalSize()) { - case 2: return SH_BOOL_VEC2; - case 3: return SH_BOOL_VEC3; - case 4: return SH_BOOL_VEC4; - default: UNREACHABLE(); - } - } else { - return SH_BOOL; - } - case EbtSampler2D: return SH_SAMPLER_2D; - case EbtSamplerCube: return SH_SAMPLER_CUBE; - case EbtSamplerExternalOES: return SH_SAMPLER_EXTERNAL_OES; - case EbtSampler2DRect: return SH_SAMPLER_2D_RECT_ARB; - default: UNREACHABLE(); - } - return SH_NONE; -} - -void getBuiltInVariableInfo(const TType& type, - const TString& name, - const TString& mappedName, - TVariableInfoList& infoList); -void getUserDefinedVariableInfo(const TType& type, - const TString& name, - const TString& mappedName, - TVariableInfoList& infoList, - ShHashFunction64 hashFunction); +template +static void ExpandUserDefinedVariable(const VarT &variable, + const std::string &name, + const std::string &mappedName, + bool markStaticUse, + std::vector *expanded); // Returns info for an attribute, uniform, or varying. -void getVariableInfo(const TType& type, - const TString& name, - const TString& mappedName, - TVariableInfoList& infoList, - ShHashFunction64 hashFunction) +template +static void ExpandVariable(const VarT &variable, + const std::string &name, + const std::string &mappedName, + bool markStaticUse, + std::vector *expanded) { - if (type.getBasicType() == EbtStruct) { - if (type.isArray()) { - for (int i = 0; i < type.getArraySize(); ++i) { - TString lname = name + arrayBrackets(i); - TString lmappedName = mappedName + arrayBrackets(i); - getUserDefinedVariableInfo(type, lname, lmappedName, infoList, hashFunction); + if (variable.isStruct()) + { + if (variable.isArray()) + { + for (size_t elementIndex = 0; elementIndex < variable.elementCount(); elementIndex++) + { + std::string lname = name + ArrayString(elementIndex); + std::string lmappedName = mappedName + ArrayString(elementIndex); + ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded); } - } else { - getUserDefinedVariableInfo(type, name, mappedName, infoList, hashFunction); } - } else { - getBuiltInVariableInfo(type, name, mappedName, infoList); + else + { + ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded); + } } -} + else + { + VarT expandedVar = variable; -void getBuiltInVariableInfo(const TType& type, - const TString& name, - const TString& mappedName, - TVariableInfoList& infoList) -{ - ASSERT(type.getBasicType() != EbtStruct); - - TVariableInfo varInfo; - if (type.isArray()) { - varInfo.name = (name + "[0]").c_str(); - varInfo.mappedName = (mappedName + "[0]").c_str(); - varInfo.size = type.getArraySize(); - varInfo.isArray = true; - } else { - varInfo.name = name.c_str(); - varInfo.mappedName = mappedName.c_str(); - varInfo.size = 1; - varInfo.isArray = false; + expandedVar.name = name; + expandedVar.mappedName = mappedName; + + // Mark all expanded fields as used if the parent is used + if (markStaticUse) + { + expandedVar.staticUse = true; + } + + if (expandedVar.isArray()) + { + expandedVar.name += "[0]"; + expandedVar.mappedName += "[0]"; + } + + expanded->push_back(expandedVar); } - varInfo.precision = type.getPrecision(); - varInfo.type = getVariableDataType(type); - infoList.push_back(varInfo); } -void getUserDefinedVariableInfo(const TType& type, - const TString& name, - const TString& mappedName, - TVariableInfoList& infoList, - ShHashFunction64 hashFunction) +template +static void ExpandUserDefinedVariable(const VarT &variable, + const std::string &name, + const std::string &mappedName, + bool markStaticUse, + std::vector *expanded) { - ASSERT(type.getBasicType() == EbtStruct); - - const TFieldList& fields = type.getStruct()->fields(); - for (size_t i = 0; i < fields.size(); ++i) { - const TType& fieldType = *(fields[i]->type()); - const TString& fieldName = fields[i]->name(); - getVariableInfo(fieldType, - name + "." + fieldName, - mappedName + "." + TIntermTraverser::hash(fieldName, hashFunction), - infoList, - hashFunction); + ASSERT(variable.isStruct()); + + const std::vector &fields = variable.fields; + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + const VarT &field = fields[fieldIndex]; + ExpandVariable(field, + name + "." + field.name, + mappedName + "." + field.mappedName, + markStaticUse, + expanded); } } -TVariableInfo* findVariable(const TType& type, - const TString& name, - TVariableInfoList& infoList) +template +static VarT *FindVariable(const TString &name, + std::vector *infoList) { // TODO(zmo): optimize this function. - TString myName = name; - if (type.isArray()) - myName += "[0]"; - for (size_t ii = 0; ii < infoList.size(); ++ii) + for (size_t ii = 0; ii < infoList->size(); ++ii) { - if (infoList[ii].name.c_str() == myName) - return &(infoList[ii]); + if ((*infoList)[ii].name.c_str() == name) + return &((*infoList)[ii]); } - return NULL; -} - -} // namespace anonymous - -TVariableInfo::TVariableInfo() - : type(SH_NONE), - size(0), - isArray(false), - precision(EbpUndefined), - staticUse(false) -{ -} -TVariableInfo::TVariableInfo(ShDataType type, int size) - : type(type), - size(size), - isArray(false), - precision(EbpUndefined), - staticUse(false) -{ + return NULL; } -CollectVariables::CollectVariables(TVariableInfoList& attribs, - TVariableInfoList& uniforms, - TVariableInfoList& varyings, +CollectVariables::CollectVariables(std::vector *attribs, + std::vector *outputVariables, + std::vector *uniforms, + std::vector *varyings, + std::vector *interfaceBlocks, ShHashFunction64 hashFunction) : mAttribs(attribs), + mOutputVariables(outputVariables), mUniforms(uniforms), mVaryings(varyings), + mInterfaceBlocks(interfaceBlocks), mPointCoordAdded(false), mFrontFacingAdded(false), mFragCoordAdded(false), @@ -203,110 +122,254 @@ CollectVariables::CollectVariables(TVariableInfoList& attribs, // Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count // toward varying counting if they are statically used in a fragment // shader. -void CollectVariables::visitSymbol(TIntermSymbol* symbol) +void CollectVariables::visitSymbol(TIntermSymbol *symbol) { ASSERT(symbol != NULL); - TVariableInfo* var = NULL; - switch (symbol->getQualifier()) + sh::ShaderVariable *var = NULL; + const TString &symbolName = symbol->getSymbol(); + + if (sh::IsVarying(symbol->getQualifier())) { - case EvqVaryingOut: - case EvqInvariantVaryingOut: - case EvqVaryingIn: - case EvqInvariantVaryingIn: - var = findVariable(symbol->getType(), symbol->getSymbol(), mVaryings); - break; - case EvqUniform: - var = findVariable(symbol->getType(), symbol->getSymbol(), mUniforms); - break; - case EvqFragCoord: - if (!mFragCoordAdded) { - TVariableInfo info; - info.name = "gl_FragCoord"; - info.mappedName = "gl_FragCoord"; - info.type = SH_FLOAT_VEC4; - info.size = 1; - info.precision = EbpMedium; // Use mediump as it doesn't really matter. - info.staticUse = true; - mVaryings.push_back(info); - mFragCoordAdded = true; - } - return; - case EvqFrontFacing: - if (!mFrontFacingAdded) { - TVariableInfo info; - info.name = "gl_FrontFacing"; - info.mappedName = "gl_FrontFacing"; - info.type = SH_BOOL; - info.size = 1; - info.precision = EbpUndefined; - info.staticUse = true; - mVaryings.push_back(info); - mFrontFacingAdded = true; - } - return; - case EvqPointCoord: - if (!mPointCoordAdded) { - TVariableInfo info; - info.name = "gl_PointCoord"; - info.mappedName = "gl_PointCoord"; - info.type = SH_FLOAT_VEC2; - info.size = 1; - info.precision = EbpMedium; // Use mediump as it doesn't really matter. - info.staticUse = true; - mVaryings.push_back(info); - mPointCoordAdded = true; + var = FindVariable(symbolName, mVaryings); + } + else if (symbol->getType() != EbtInterfaceBlock) + { + switch (symbol->getQualifier()) + { + case EvqAttribute: + case EvqVertexIn: + var = FindVariable(symbolName, mAttribs); + break; + case EvqFragmentOut: + var = FindVariable(symbolName, mOutputVariables); + break; + case EvqUniform: + { + const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock(); + if (interfaceBlock) + { + sh::InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks); + ASSERT(namedBlock); + var = FindVariable(symbolName, &namedBlock->fields); + + // Set static use on the parent interface block here + namedBlock->staticUse = true; + } + else + { + var = FindVariable(symbolName, mUniforms); + } + + // It's an internal error to reference an undefined user uniform + ASSERT(symbolName.compare(0, 3, "gl_") == 0 || var); + } + break; + case EvqFragCoord: + if (!mFragCoordAdded) + { + sh::Varying info; + info.name = "gl_FragCoord"; + info.mappedName = "gl_FragCoord"; + info.type = GL_FLOAT_VEC4; + info.arraySize = 0; + info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter. + info.staticUse = true; + mVaryings->push_back(info); + mFragCoordAdded = true; + } + return; + case EvqFrontFacing: + if (!mFrontFacingAdded) + { + sh::Varying info; + info.name = "gl_FrontFacing"; + info.mappedName = "gl_FrontFacing"; + info.type = GL_BOOL; + info.arraySize = 0; + info.precision = GL_NONE; + info.staticUse = true; + mVaryings->push_back(info); + mFrontFacingAdded = true; + } + return; + case EvqPointCoord: + if (!mPointCoordAdded) + { + sh::Varying info; + info.name = "gl_PointCoord"; + info.mappedName = "gl_PointCoord"; + info.type = GL_FLOAT_VEC2; + info.arraySize = 0; + info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter. + info.staticUse = true; + mVaryings->push_back(info); + mPointCoordAdded = true; + } + return; + default: + break; } - return; - default: - break; } if (var) + { var->staticUse = true; + } +} + +template +class NameHashingTraverser : public sh::GetVariableTraverser +{ + public: + NameHashingTraverser(std::vector *output, ShHashFunction64 hashFunction) + : sh::GetVariableTraverser(output), + mHashFunction(hashFunction) + {} + + private: + void visitVariable(VarT *variable) + { + TString stringName = TString(variable->name.c_str()); + variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str(); + } + + ShHashFunction64 mHashFunction; +}; + +// Attributes, which cannot have struct fields, are a special case +template <> +void CollectVariables::visitVariable(const TIntermSymbol *variable, + std::vector *infoList) const +{ + ASSERT(variable); + const TType &type = variable->getType(); + ASSERT(!type.getStruct()); + + sh::Attribute attribute; + + attribute.type = sh::GLVariableType(type); + attribute.precision = sh::GLVariablePrecision(type); + attribute.name = variable->getSymbol().c_str(); + attribute.arraySize = static_cast(type.getArraySize()); + attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str(); + attribute.location = variable->getType().getLayoutQualifier().location; + + infoList->push_back(attribute); } -bool CollectVariables::visitAggregate(Visit, TIntermAggregate* node) +template <> +void CollectVariables::visitVariable(const TIntermSymbol *variable, + std::vector *infoList) const +{ + sh::InterfaceBlock interfaceBlock; + const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock(); + + bool isRowMajor = (blockType->matrixPacking() == EmpRowMajor); + + interfaceBlock.name = blockType->name().c_str(); + interfaceBlock.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str(); + interfaceBlock.arraySize = variable->getArraySize(); + interfaceBlock.isRowMajorLayout = isRowMajor; + interfaceBlock.layout = sh::GetBlockLayoutType(blockType->blockStorage()); + + ASSERT(blockType); + const TFieldList &blockFields = blockType->fields(); + + for (size_t fieldIndex = 0; fieldIndex < blockFields.size(); fieldIndex++) + { + const TField *field = blockFields[fieldIndex]; + ASSERT(field); + + sh::GetInterfaceBlockFieldTraverser traverser(&interfaceBlock.fields, isRowMajor); + traverser.traverse(*field->type(), field->name()); + } + + infoList->push_back(interfaceBlock); +} + +template +void CollectVariables::visitVariable(const TIntermSymbol *variable, + std::vector *infoList) const +{ + NameHashingTraverser traverser(infoList, mHashFunction); + traverser.traverse(variable->getType(), variable->getSymbol()); +} + +template +void CollectVariables::visitInfoList(const TIntermSequence &sequence, + std::vector *infoList) const +{ + for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++) + { + const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode(); + // The only case in which the sequence will not contain a + // TIntermSymbol node is initialization. It will contain a + // TInterBinary node in that case. Since attributes, uniforms, + // and varyings cannot be initialized in a shader, we must have + // only TIntermSymbol nodes in the sequence. + ASSERT(variable != NULL); + visitVariable(variable, infoList); + } +} + +bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node) { bool visitChildren = true; switch (node->getOp()) { - case EOpDeclaration: { - const TIntermSequence& sequence = node->getSequence(); - TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier(); - if (qualifier == EvqAttribute || qualifier == EvqUniform || - qualifier == EvqVaryingIn || qualifier == EvqVaryingOut || - qualifier == EvqInvariantVaryingIn || qualifier == EvqInvariantVaryingOut) + case EOpDeclaration: { - TVariableInfoList& infoList = qualifier == EvqAttribute ? mAttribs : - (qualifier == EvqUniform ? mUniforms : mVaryings); - for (TIntermSequence::const_iterator i = sequence.begin(); - i != sequence.end(); ++i) + const TIntermSequence &sequence = *(node->getSequence()); + const TIntermTyped &typedNode = *(sequence.front()->getAsTyped()); + TQualifier qualifier = typedNode.getQualifier(); + + if (typedNode.getBasicType() == EbtInterfaceBlock) { - const TIntermSymbol* variable = (*i)->getAsSymbolNode(); - // The only case in which the sequence will not contain a - // TIntermSymbol node is initialization. It will contain a - // TInterBinary node in that case. Since attributes, uniforms, - // and varyings cannot be initialized in a shader, we must have - // only TIntermSymbol nodes in the sequence. - ASSERT(variable != NULL); - TString processedSymbol; - if (mHashFunction == NULL) - processedSymbol = variable->getSymbol(); - else - processedSymbol = TIntermTraverser::hash(variable->getOriginalSymbol(), mHashFunction); - getVariableInfo(variable->getType(), - variable->getOriginalSymbol(), - processedSymbol, - infoList, - mHashFunction); - visitChildren = false; + visitInfoList(sequence, mInterfaceBlocks); + } + else if (qualifier == EvqAttribute || qualifier == EvqVertexIn || + qualifier == EvqFragmentOut || qualifier == EvqUniform || + sh::IsVarying(qualifier)) + { + switch (qualifier) + { + case EvqAttribute: + case EvqVertexIn: + visitInfoList(sequence, mAttribs); + break; + case EvqFragmentOut: + visitInfoList(sequence, mOutputVariables); + break; + case EvqUniform: + visitInfoList(sequence, mUniforms); + break; + default: + visitInfoList(sequence, mVaryings); + break; + } + + if (!sequence.empty()) + { + visitChildren = false; + } } + break; } - break; - } - default: break; + default: break; } return visitChildren; } +template +void ExpandVariables(const std::vector &compact, std::vector *expanded) +{ + for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++) + { + const VarT &variable = compact[variableIndex]; + ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded); + } +} + +template void ExpandVariables(const std::vector &, std::vector *); +template void ExpandVariables(const std::vector &, std::vector *); diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h index 37216cd142..3771819c8b 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h +++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h @@ -7,40 +7,37 @@ #ifndef COMPILER_VARIABLE_INFO_H_ #define COMPILER_VARIABLE_INFO_H_ -#include "GLSLANG/ShaderLang.h" #include "compiler/translator/intermediate.h" - -// Provides information about a variable. -// It is currently being used to store info about active attribs and uniforms. -struct TVariableInfo { - TVariableInfo(ShDataType type, int size); - TVariableInfo(); - - TPersistString name; - TPersistString mappedName; - ShDataType type; - int size; - bool isArray; - TPrecision precision; - bool staticUse; -}; -typedef std::vector TVariableInfoList; +#include "common/shadervars.h" // Traverses intermediate tree to collect all attributes, uniforms, varyings. -class CollectVariables : public TIntermTraverser { -public: - CollectVariables(TVariableInfoList& attribs, - TVariableInfoList& uniforms, - TVariableInfoList& varyings, +class CollectVariables : public TIntermTraverser +{ + public: + CollectVariables(std::vector *attribs, + std::vector *outputVariables, + std::vector *uniforms, + std::vector *varyings, + std::vector *interfaceBlocks, ShHashFunction64 hashFunction); - virtual void visitSymbol(TIntermSymbol*); - virtual bool visitAggregate(Visit, TIntermAggregate*); + virtual void visitSymbol(TIntermSymbol *symbol); + virtual bool visitAggregate(Visit, TIntermAggregate *node); + + private: + template + void visitVariable(const TIntermSymbol *variable, std::vector *infoList) const; -private: - TVariableInfoList& mAttribs; - TVariableInfoList& mUniforms; - TVariableInfoList& mVaryings; + template + void visitInfoList(const TIntermSequence &sequence, std::vector *infoList) const; + + std::vector *mAttribs; + std::vector *mOutputVariables; + std::vector *mUniforms; + std::vector *mVaryings; + std::vector *mInterfaceBlocks; + + std::map mInterfaceBlockFields; bool mPointCoordAdded; bool mFrontFacingAdded; @@ -49,4 +46,9 @@ private: ShHashFunction64 mHashFunction; }; +// Expand struct variables to flattened lists of split variables +// Implemented for sh::Varying and sh::Uniform. +template +void ExpandVariables(const std::vector &compact, std::vector *expanded); + #endif // COMPILER_VARIABLE_INFO_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/VariablePacker.cpp b/src/3rdparty/angle/src/compiler/translator/VariablePacker.cpp index 5634d86337..faaf0115fc 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariablePacker.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VariablePacker.cpp @@ -4,121 +4,78 @@ // found in the LICENSE file. // #include "compiler/translator/VariablePacker.h" +#include "angle_gl.h" +#include "common/utilities.h" #include -#include "compiler/translator/ShHandle.h" -namespace { -int GetSortOrder(ShDataType type) +int VariablePacker::GetNumComponentsPerRow(sh::GLenum type) { - switch (type) { - case SH_FLOAT_MAT4: - return 0; - case SH_FLOAT_MAT2: - return 1; - case SH_FLOAT_VEC4: - case SH_INT_VEC4: - case SH_BOOL_VEC4: - return 2; - case SH_FLOAT_MAT3: - return 3; - case SH_FLOAT_VEC3: - case SH_INT_VEC3: - case SH_BOOL_VEC3: - return 4; - case SH_FLOAT_VEC2: - case SH_INT_VEC2: - case SH_BOOL_VEC2: - return 5; - case SH_FLOAT: - case SH_INT: - case SH_BOOL: - case SH_SAMPLER_2D: - case SH_SAMPLER_CUBE: - case SH_SAMPLER_EXTERNAL_OES: - case SH_SAMPLER_2D_RECT_ARB: - return 6; - default: - ASSERT(false); - return 7; + switch (type) + { + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_BOOL_VEC4: + case GL_UNSIGNED_INT_VEC4: + return 4; + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_BOOL_VEC3: + case GL_UNSIGNED_INT_VEC3: + return 3; + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_BOOL_VEC2: + case GL_UNSIGNED_INT_VEC2: + return 2; + default: + ASSERT(gl::VariableComponentCount(type) == 1); + return 1; } } -} // namespace -int VariablePacker::GetNumComponentsPerRow(ShDataType type) +int VariablePacker::GetNumRows(sh::GLenum type) { - switch (type) { - case SH_FLOAT_MAT4: - case SH_FLOAT_MAT2: - case SH_FLOAT_VEC4: - case SH_INT_VEC4: - case SH_BOOL_VEC4: - return 4; - case SH_FLOAT_MAT3: - case SH_FLOAT_VEC3: - case SH_INT_VEC3: - case SH_BOOL_VEC3: - return 3; - case SH_FLOAT_VEC2: - case SH_INT_VEC2: - case SH_BOOL_VEC2: - return 2; - case SH_FLOAT: - case SH_INT: - case SH_BOOL: - case SH_SAMPLER_2D: - case SH_SAMPLER_CUBE: - case SH_SAMPLER_EXTERNAL_OES: - case SH_SAMPLER_2D_RECT_ARB: - return 1; - default: - ASSERT(false); - return 5; + switch (type) + { + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x3: + case GL_FLOAT_MAT4x2: + return 4; + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT3x2: + return 3; + case GL_FLOAT_MAT2: + return 2; + default: + ASSERT(gl::VariableRowCount(type) == 1); + return 1; } } -int VariablePacker::GetNumRows(ShDataType type) +struct TVariableInfoComparer { - switch (type) { - case SH_FLOAT_MAT4: - return 4; - case SH_FLOAT_MAT3: - return 3; - case SH_FLOAT_MAT2: - return 2; - case SH_FLOAT_VEC4: - case SH_INT_VEC4: - case SH_BOOL_VEC4: - case SH_FLOAT_VEC3: - case SH_INT_VEC3: - case SH_BOOL_VEC3: - case SH_FLOAT_VEC2: - case SH_INT_VEC2: - case SH_BOOL_VEC2: - case SH_FLOAT: - case SH_INT: - case SH_BOOL: - case SH_SAMPLER_2D: - case SH_SAMPLER_CUBE: - case SH_SAMPLER_EXTERNAL_OES: - case SH_SAMPLER_2D_RECT_ARB: - return 1; - default: - ASSERT(false); - return 100000; - } -} - -struct TVariableInfoComparer { - bool operator()(const TVariableInfo& lhs, const TVariableInfo& rhs) const + bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const { - int lhsSortOrder = GetSortOrder(lhs.type); - int rhsSortOrder = GetSortOrder(rhs.type); + int lhsSortOrder = gl::VariableSortOrder(lhs.type); + int rhsSortOrder = gl::VariableSortOrder(rhs.type); if (lhsSortOrder != rhsSortOrder) { return lhsSortOrder < rhsSortOrder; } // Sort by largest first. - return lhs.size > rhs.size; + return lhs.arraySize > rhs.arraySize; } }; @@ -189,13 +146,23 @@ bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* de return true; } -bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVariableInfoList& in_variables) +template +bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int maxVectors, + const std::vector &in_variables) { ASSERT(maxVectors > 0); maxRows_ = maxVectors; topNonFullRow_ = 0; bottomNonFullRow_ = maxRows_ - 1; - TVariableInfoList variables(in_variables); + std::vector variables(in_variables); + + // Check whether each variable fits in the available vectors. + for (size_t i = 0; i < variables.size(); i++) { + const sh::ShaderVariable &variable = variables[i]; + if (variable.elementCount() > maxVectors / GetNumRows(variable.type)) { + return false; + } + } // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific // order by type, then by size of array, largest first. @@ -206,11 +173,11 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa // Packs the 4 column variables. size_t ii = 0; for (; ii < variables.size(); ++ii) { - const TVariableInfo& variable = variables[ii]; + const sh::ShaderVariable &variable = variables[ii]; if (GetNumComponentsPerRow(variable.type) != 4) { break; } - topNonFullRow_ += GetNumRows(variable.type) * variable.size; + topNonFullRow_ += GetNumRows(variable.type) * variable.elementCount(); } if (topNonFullRow_ > maxRows_) { @@ -220,11 +187,11 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa // Packs the 3 column variables. int num3ColumnRows = 0; for (; ii < variables.size(); ++ii) { - const TVariableInfo& variable = variables[ii]; + const sh::ShaderVariable &variable = variables[ii]; if (GetNumComponentsPerRow(variable.type) != 3) { break; } - num3ColumnRows += GetNumRows(variable.type) * variable.size; + num3ColumnRows += GetNumRows(variable.type) * variable.elementCount(); } if (topNonFullRow_ + num3ColumnRows > maxRows_) { @@ -239,11 +206,11 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa int rowsAvailableInColumns01 = twoColumnRowsAvailable; int rowsAvailableInColumns23 = twoColumnRowsAvailable; for (; ii < variables.size(); ++ii) { - const TVariableInfo& variable = variables[ii]; + const sh::ShaderVariable &variable = variables[ii]; if (GetNumComponentsPerRow(variable.type) != 2) { break; } - int numRows = GetNumRows(variable.type) * variable.size; + int numRows = GetNumRows(variable.type) * variable.elementCount(); if (numRows <= rowsAvailableInColumns01) { rowsAvailableInColumns01 -= numRows; } else if (numRows <= rowsAvailableInColumns23) { @@ -263,9 +230,9 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa // Packs the 1 column variables. for (; ii < variables.size(); ++ii) { - const TVariableInfo& variable = variables[ii]; + const sh::ShaderVariable &variable = variables[ii]; ASSERT(1 == GetNumComponentsPerRow(variable.type)); - int numRows = GetNumRows(variable.type) * variable.size; + int numRows = GetNumRows(variable.type) * variable.elementCount(); int smallestColumn = -1; int smallestSize = maxRows_ + 1; int topRow = -1; @@ -293,5 +260,8 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVa return true; } - - +// Instantiate all possible variable packings +template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector &); +template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector &); +template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector &); +template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector &); diff --git a/src/3rdparty/angle/src/compiler/translator/VariablePacker.h b/src/3rdparty/angle/src/compiler/translator/VariablePacker.h index fd6090827c..1de5332d8a 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariablePacker.h +++ b/src/3rdparty/angle/src/compiler/translator/VariablePacker.h @@ -8,23 +8,23 @@ #define _VARIABLEPACKER_INCLUDED_ #include -#include "compiler/translator/ShHandle.h" +#include "compiler/translator/VariableInfo.h" class VariablePacker { public: // Returns true if the passed in variables pack in maxVectors following // the packing rules from the GLSL 1.017 spec, Appendix A, section 7. - bool CheckVariablesWithinPackingLimits( - int maxVectors, - const TVariableInfoList& in_variables); + template + bool CheckVariablesWithinPackingLimits(unsigned int maxVectors, + const std::vector &in_variables); // Gets how many components in a row a data type takes. - static int GetNumComponentsPerRow(ShDataType type); + static int GetNumComponentsPerRow(sh::GLenum type); // Gets how many rows a data type takes. - static int GetNumRows(ShDataType type); + static int GetNumRows(sh::GLenum type); - private: + private: static const int kNumColumns = 4; static const unsigned kColumnMask = (1 << kNumColumns) - 1; diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp index dd11f99eb8..12dc9e0dad 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp @@ -35,104 +35,81 @@ static const int GLSL_VERSION_120 = 120; // - invariant gl_Position; // - varying vec3 color; invariant color; // -TVersionGLSL::TVersionGLSL(ShShaderType type) - : mShaderType(type), - mVersion(GLSL_VERSION_110) +TVersionGLSL::TVersionGLSL(sh::GLenum type) + : mVersion(GLSL_VERSION_110) { } -void TVersionGLSL::visitSymbol(TIntermSymbol* node) +void TVersionGLSL::visitSymbol(TIntermSymbol *node) { if (node->getSymbol() == "gl_PointCoord") updateVersion(GLSL_VERSION_120); } -void TVersionGLSL::visitConstantUnion(TIntermConstantUnion*) -{ -} - -bool TVersionGLSL::visitBinary(Visit, TIntermBinary*) -{ - return true; -} - -bool TVersionGLSL::visitUnary(Visit, TIntermUnary*) -{ - return true; -} - -bool TVersionGLSL::visitSelection(Visit, TIntermSelection*) -{ - return true; -} - -bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate* node) +bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node) { bool visitChildren = true; - switch (node->getOp()) { + switch (node->getOp()) + { case EOpSequence: // We need to visit sequence children to get to global or inner scope. visitChildren = true; break; - case EOpDeclaration: { - const TIntermSequence& sequence = node->getSequence(); - TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier(); - if ((qualifier == EvqInvariantVaryingIn) || - (qualifier == EvqInvariantVaryingOut)) { - updateVersion(GLSL_VERSION_120); + case EOpDeclaration: + { + const TIntermSequence &sequence = *(node->getSequence()); + TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier(); + if ((qualifier == EvqInvariantVaryingIn) || + (qualifier == EvqInvariantVaryingOut)) + { + updateVersion(GLSL_VERSION_120); + } + break; } - break; - } - case EOpParameters: { - const TIntermSequence& params = node->getSequence(); - for (TIntermSequence::const_iterator iter = params.begin(); - iter != params.end(); ++iter) + case EOpParameters: { - const TIntermTyped* param = (*iter)->getAsTyped(); - if (param->isArray()) + const TIntermSequence ¶ms = *(node->getSequence()); + for (TIntermSequence::const_iterator iter = params.begin(); + iter != params.end(); ++iter) { - TQualifier qualifier = param->getQualifier(); - if ((qualifier == EvqOut) || (qualifier == EvqInOut)) + const TIntermTyped *param = (*iter)->getAsTyped(); + if (param->isArray()) { - updateVersion(GLSL_VERSION_120); - break; + TQualifier qualifier = param->getQualifier(); + if ((qualifier == EvqOut) || (qualifier == EvqInOut)) + { + updateVersion(GLSL_VERSION_120); + break; + } } } + // Fully processed. No need to visit children. + visitChildren = false; + break; } - // Fully processed. No need to visit children. - visitChildren = false; - break; - } case EOpConstructMat2: case EOpConstructMat3: - case EOpConstructMat4: { - const TIntermSequence& sequence = node->getSequence(); - if (sequence.size() == 1) { - TIntermTyped* typed = sequence.front()->getAsTyped(); - if (typed && typed->isMatrix()) { - updateVersion(GLSL_VERSION_120); - } + case EOpConstructMat4: + { + const TIntermSequence &sequence = *(node->getSequence()); + if (sequence.size() == 1) + { + TIntermTyped *typed = sequence.front()->getAsTyped(); + if (typed && typed->isMatrix()) + { + updateVersion(GLSL_VERSION_120); + } + } + break; } + default: break; - } - - default: break; } return visitChildren; } -bool TVersionGLSL::visitLoop(Visit, TIntermLoop*) -{ - return true; -} - -bool TVersionGLSL::visitBranch(Visit, TIntermBranch*) -{ - return true; -} - void TVersionGLSL::updateVersion(int version) { mVersion = std::max(version, mVersion); diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h index d310066171..de4141d38c 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h @@ -1,13 +1,12 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // -#ifndef COMPILER_VERSIONGLSL_H_ -#define COMPILER_VERSIONGLSL_H_ +#ifndef COMPILER_TRANSLATOR_VERSIONGLSL_H_ +#define COMPILER_TRANSLATOR_VERSIONGLSL_H_ -#include "GLSLANG/ShaderLang.h" #include "compiler/translator/intermediate.h" // Traverses the intermediate tree to return the minimum GLSL version @@ -24,9 +23,11 @@ // - matrix constructors taking matrix as argument. // - array as "out" function parameters // -class TVersionGLSL : public TIntermTraverser { -public: - TVersionGLSL(ShShaderType type); +// TODO: ES3 equivalent versions of GLSL +class TVersionGLSL : public TIntermTraverser +{ + public: + TVersionGLSL(sh::GLenum type); // Returns 120 if the following is used the shader: // - "invariant", @@ -36,21 +37,14 @@ public: // Else 110 is returned. int getVersion() { return mVersion; } - virtual void visitSymbol(TIntermSymbol*); - virtual void visitConstantUnion(TIntermConstantUnion*); - virtual bool visitBinary(Visit, TIntermBinary*); - virtual bool visitUnary(Visit, TIntermUnary*); - virtual bool visitSelection(Visit, TIntermSelection*); - virtual bool visitAggregate(Visit, TIntermAggregate*); - virtual bool visitLoop(Visit, TIntermLoop*); - virtual bool visitBranch(Visit, TIntermBranch*); + virtual void visitSymbol(TIntermSymbol *); + virtual bool visitAggregate(Visit, TIntermAggregate *); -protected: + protected: void updateVersion(int version); -private: - ShShaderType mShaderType; + private: int mVersion; }; -#endif // COMPILER_VERSIONGLSL_H_ +#endif // COMPILER_TRANSLATOR_VERSIONGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp index d5f2cba5fc..1aeb822d51 100644 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp +++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp @@ -6,24 +6,32 @@ #include "compiler/translator/depgraph/DependencyGraphBuilder.h" -void TDependencyGraphBuilder::build(TIntermNode* node, TDependencyGraph* graph) +void TDependencyGraphBuilder::build(TIntermNode *node, TDependencyGraph *graph) { TDependencyGraphBuilder builder(graph); builder.build(node); } -bool TDependencyGraphBuilder::visitAggregate(Visit visit, TIntermAggregate* intermAggregate) +bool TDependencyGraphBuilder::visitAggregate( + Visit visit, TIntermAggregate *intermAggregate) { - switch (intermAggregate->getOp()) { - case EOpFunction: visitFunctionDefinition(intermAggregate); break; - case EOpFunctionCall: visitFunctionCall(intermAggregate); break; - default: visitAggregateChildren(intermAggregate); break; + switch (intermAggregate->getOp()) + { + case EOpFunction: + visitFunctionDefinition(intermAggregate); + break; + case EOpFunctionCall: + visitFunctionCall(intermAggregate); + break; + default: + visitAggregateChildren(intermAggregate); + break; } - return false; } -void TDependencyGraphBuilder::visitFunctionDefinition(TIntermAggregate* intermAggregate) +void TDependencyGraphBuilder::visitFunctionDefinition( + TIntermAggregate *intermAggregate) { // Currently, we do not support user defined functions. if (intermAggregate->getName() != "main(") @@ -34,64 +42,71 @@ void TDependencyGraphBuilder::visitFunctionDefinition(TIntermAggregate* intermAg // Takes an expression like "f(x)" and creates a dependency graph like // "x -> argument 0 -> function call". -void TDependencyGraphBuilder::visitFunctionCall(TIntermAggregate* intermFunctionCall) +void TDependencyGraphBuilder::visitFunctionCall( + TIntermAggregate *intermFunctionCall) { - TGraphFunctionCall* functionCall = mGraph->createFunctionCall(intermFunctionCall); + TGraphFunctionCall *functionCall = + mGraph->createFunctionCall(intermFunctionCall); // Run through the function call arguments. int argumentNumber = 0; - TIntermSequence& intermArguments = intermFunctionCall->getSequence(); - for (TIntermSequence::const_iterator iter = intermArguments.begin(); - iter != intermArguments.end(); + TIntermSequence *intermArguments = intermFunctionCall->getSequence(); + for (TIntermSequence::const_iterator iter = intermArguments->begin(); + iter != intermArguments->end(); ++iter, ++argumentNumber) { TNodeSetMaintainer nodeSetMaintainer(this); - TIntermNode* intermArgument = *iter; + TIntermNode *intermArgument = *iter; intermArgument->traverse(this); - if (TParentNodeSet* argumentNodes = mNodeSets.getTopSet()) { - TGraphArgument* argument = mGraph->createArgument(intermFunctionCall, argumentNumber); + if (TParentNodeSet *argumentNodes = mNodeSets.getTopSet()) + { + TGraphArgument *argument = mGraph->createArgument( + intermFunctionCall, argumentNumber); connectMultipleNodesToSingleNode(argumentNodes, argument); argument->addDependentNode(functionCall); } } - // Push the leftmost symbol of this function call into the current set of dependent symbols to - // represent the result of this function call. + // Push the leftmost symbol of this function call into the current set of + // dependent symbols to represent the result of this function call. // Thus, an expression like "y = f(x)" will yield a dependency graph like // "x -> argument 0 -> function call -> y". - // This line essentially passes the function call node back up to an earlier visitAssignment - // call, which will create the connection "function call -> y". + // This line essentially passes the function call node back up to an earlier + // visitAssignment call, which will create the connection "function call -> y". mNodeSets.insertIntoTopSet(functionCall); } -void TDependencyGraphBuilder::visitAggregateChildren(TIntermAggregate* intermAggregate) +void TDependencyGraphBuilder::visitAggregateChildren( + TIntermAggregate *intermAggregate) { - TIntermSequence& sequence = intermAggregate->getSequence(); - for(TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter) + TIntermSequence *sequence = intermAggregate->getSequence(); + for (TIntermSequence::const_iterator iter = sequence->begin(); + iter != sequence->end(); ++iter) { - TIntermNode* intermChild = *iter; + TIntermNode *intermChild = *iter; intermChild->traverse(this); } } -void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol) +void TDependencyGraphBuilder::visitSymbol(TIntermSymbol *intermSymbol) { - // Push this symbol into the set of dependent symbols for the current assignment or condition - // that we are traversing. - TGraphSymbol* symbol = mGraph->getOrCreateSymbol(intermSymbol); + // Push this symbol into the set of dependent symbols for the current + // assignment or condition that we are traversing. + TGraphSymbol *symbol = mGraph->getOrCreateSymbol(intermSymbol); mNodeSets.insertIntoTopSet(symbol); - // If this symbol is the current leftmost symbol under an assignment, replace the previous - // leftmost symbol with this symbol. - if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) { + // If this symbol is the current leftmost symbol under an assignment, replace + // the previous leftmost symbol with this symbol. + if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) + { mLeftmostSymbols.pop(); mLeftmostSymbols.push(symbol); } } -bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary) +bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary *intermBinary) { TOperator op = intermBinary->getOp(); if (op == EOpInitialize || intermBinary->isAssignment()) @@ -104,13 +119,13 @@ bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBina return false; } -void TDependencyGraphBuilder::visitAssignment(TIntermBinary* intermAssignment) +void TDependencyGraphBuilder::visitAssignment(TIntermBinary *intermAssignment) { - TIntermTyped* intermLeft = intermAssignment->getLeft(); + TIntermTyped *intermLeft = intermAssignment->getLeft(); if (!intermLeft) return; - TGraphSymbol* leftmostSymbol = NULL; + TGraphSymbol *leftmostSymbol = NULL; { TNodeSetMaintainer nodeSetMaintainer(this); @@ -120,88 +135,100 @@ void TDependencyGraphBuilder::visitAssignment(TIntermBinary* intermAssignment) intermLeft->traverse(this); leftmostSymbol = mLeftmostSymbols.top(); - // After traversing the left subtree of this assignment, we should have found a real - // leftmost symbol, and the leftmost symbol should not be a placeholder. + // After traversing the left subtree of this assignment, we should + // have found a real leftmost symbol, and the leftmost symbol should + // not be a placeholder. ASSERT(leftmostSymbol != &mLeftSubtree); ASSERT(leftmostSymbol != &mRightSubtree); } - if (TIntermTyped* intermRight = intermAssignment->getRight()) { + if (TIntermTyped *intermRight = intermAssignment->getRight()) + { TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); intermRight->traverse(this); } - if (TParentNodeSet* assignmentNodes = mNodeSets.getTopSet()) + if (TParentNodeSet *assignmentNodes = mNodeSets.getTopSet()) connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol); } - // Push the leftmost symbol of this assignment into the current set of dependent symbols to - // represent the result of this assignment. - // An expression like "a = (b = c)" will yield a dependency graph like "c -> b -> a". - // This line essentially passes the leftmost symbol of the nested assignment ("b" in this - // example) back up to the earlier visitAssignment call for the outer assignment, which will - // create the connection "b -> a". + // Push the leftmost symbol of this assignment into the current set of dependent + // symbols to represent the result of this assignment. + // An expression like "a = (b = c)" will yield a dependency graph like + // "c -> b -> a". + // This line essentially passes the leftmost symbol of the nested assignment + // ("b" in this example) back up to the earlier visitAssignment call for the + // outer assignment, which will create the connection "b -> a". mNodeSets.insertIntoTopSet(leftmostSymbol); } -void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary* intermLogicalOp) +void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary *intermLogicalOp) { - if (TIntermTyped* intermLeft = intermLogicalOp->getLeft()) { + if (TIntermTyped *intermLeft = intermLogicalOp->getLeft()) + { TNodeSetPropagatingMaintainer nodeSetMaintainer(this); intermLeft->traverse(this); - if (TParentNodeSet* leftNodes = mNodeSets.getTopSet()) { - TGraphLogicalOp* logicalOp = mGraph->createLogicalOp(intermLogicalOp); + if (TParentNodeSet *leftNodes = mNodeSets.getTopSet()) + { + TGraphLogicalOp *logicalOp = mGraph->createLogicalOp(intermLogicalOp); connectMultipleNodesToSingleNode(leftNodes, logicalOp); } } - if (TIntermTyped* intermRight = intermLogicalOp->getRight()) { + if (TIntermTyped *intermRight = intermLogicalOp->getRight()) + { TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); intermRight->traverse(this); } } -void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary* intermBinary) +void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary *intermBinary) { - if (TIntermTyped* intermLeft = intermBinary->getLeft()) + if (TIntermTyped *intermLeft = intermBinary->getLeft()) intermLeft->traverse(this); - if (TIntermTyped* intermRight = intermBinary->getRight()) { + if (TIntermTyped *intermRight = intermBinary->getRight()) + { TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); intermRight->traverse(this); } } -bool TDependencyGraphBuilder::visitSelection(Visit visit, TIntermSelection* intermSelection) +bool TDependencyGraphBuilder::visitSelection( + Visit visit, TIntermSelection *intermSelection) { - if (TIntermNode* intermCondition = intermSelection->getCondition()) { + if (TIntermNode *intermCondition = intermSelection->getCondition()) + { TNodeSetMaintainer nodeSetMaintainer(this); intermCondition->traverse(this); - if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) { - TGraphSelection* selection = mGraph->createSelection(intermSelection); + if (TParentNodeSet *conditionNodes = mNodeSets.getTopSet()) + { + TGraphSelection *selection = mGraph->createSelection(intermSelection); connectMultipleNodesToSingleNode(conditionNodes, selection); } } - if (TIntermNode* intermTrueBlock = intermSelection->getTrueBlock()) + if (TIntermNode *intermTrueBlock = intermSelection->getTrueBlock()) intermTrueBlock->traverse(this); - if (TIntermNode* intermFalseBlock = intermSelection->getFalseBlock()) + if (TIntermNode *intermFalseBlock = intermSelection->getFalseBlock()) intermFalseBlock->traverse(this); return false; } -bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop* intermLoop) +bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop *intermLoop) { - if (TIntermTyped* intermCondition = intermLoop->getCondition()) { + if (TIntermTyped *intermCondition = intermLoop->getCondition()) + { TNodeSetMaintainer nodeSetMaintainer(this); intermCondition->traverse(this); - if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) { - TGraphLoop* loop = mGraph->createLoop(intermLoop); + if (TParentNodeSet *conditionNodes = mNodeSets.getTopSet()) + { + TGraphLoop *loop = mGraph->createLoop(intermLoop); connectMultipleNodesToSingleNode(conditionNodes, loop); } } @@ -209,19 +236,20 @@ bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop* intermLoop) if (TIntermNode* intermBody = intermLoop->getBody()) intermBody->traverse(this); - if (TIntermTyped* intermExpression = intermLoop->getExpression()) + if (TIntermTyped *intermExpression = intermLoop->getExpression()) intermExpression->traverse(this); return false; } -void TDependencyGraphBuilder::connectMultipleNodesToSingleNode(TParentNodeSet* nodes, - TGraphNode* node) const +void TDependencyGraphBuilder::connectMultipleNodesToSingleNode( + TParentNodeSet *nodes, TGraphNode *node) const { - for (TParentNodeSet::const_iterator iter = nodes->begin(); iter != nodes->end(); ++iter) + for (TParentNodeSet::const_iterator iter = nodes->begin(); + iter != nodes->end(); ++iter) { - TGraphParentNode* currentNode = *iter; + TGraphParentNode *currentNode = *iter; currentNode->addDependentNode(node); } } diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h index 3e928fb77e..b76f075e68 100644 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h +++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h @@ -4,55 +4,58 @@ // found in the LICENSE file. // -#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H -#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H +#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H +#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H #include "compiler/translator/depgraph/DependencyGraph.h" // -// Creates a dependency graph of symbols, function calls, conditions etc. by traversing a -// intermediate tree. +// Creates a dependency graph of symbols, function calls, conditions etc. by +// traversing a intermediate tree. // -class TDependencyGraphBuilder : public TIntermTraverser { -public: - static void build(TIntermNode* node, TDependencyGraph* graph); +class TDependencyGraphBuilder : public TIntermTraverser +{ + public: + static void build(TIntermNode *node, TDependencyGraph *graph); - virtual void visitSymbol(TIntermSymbol*); - virtual bool visitBinary(Visit visit, TIntermBinary*); - virtual bool visitSelection(Visit visit, TIntermSelection*); - virtual bool visitAggregate(Visit visit, TIntermAggregate*); - virtual bool visitLoop(Visit visit, TIntermLoop*); + virtual void visitSymbol(TIntermSymbol *); + virtual bool visitBinary(Visit visit, TIntermBinary *); + virtual bool visitSelection(Visit visit, TIntermSelection *); + virtual bool visitAggregate(Visit visit, TIntermAggregate *); + virtual bool visitLoop(Visit visit, TIntermLoop *); -private: - typedef std::stack TSymbolStack; - typedef std::set TParentNodeSet; + private: + typedef std::stack TSymbolStack; + typedef std::set TParentNodeSet; // // For collecting the dependent nodes of assignments, conditions, etc. // while traversing the intermediate tree. // - // This data structure is stack of sets. Each set contains dependency graph parent nodes. + // This data structure is stack of sets. Each set contains dependency graph + // parent nodes. // - class TNodeSetStack { - public: + class TNodeSetStack + { + public: TNodeSetStack() {}; ~TNodeSetStack() { clear(); } // This should only be called after a pushSet. // Returns NULL if the top set is empty. - TParentNodeSet* getTopSet() const + TParentNodeSet *getTopSet() const { - ASSERT(!nodeSets.empty()); - TParentNodeSet* topSet = nodeSets.top(); + ASSERT(!mNodeSets.empty()); + TParentNodeSet *topSet = mNodeSets.top(); return !topSet->empty() ? topSet : NULL; } - void pushSet() { nodeSets.push(new TParentNodeSet()); } + void pushSet() { mNodeSets.push(new TParentNodeSet()); } void popSet() { - ASSERT(!nodeSets.empty()); - delete nodeSets.top(); - nodeSets.pop(); + ASSERT(!mNodeSets.empty()); + delete mNodeSets.top(); + mNodeSets.pop(); } // Pops the top set and adds its contents to the new top set. @@ -60,12 +63,13 @@ private: // If there is no set below the top set, the top set is just deleted. void popSetIntoNext() { - ASSERT(!nodeSets.empty()); - TParentNodeSet* oldTopSet = nodeSets.top(); - nodeSets.pop(); + ASSERT(!mNodeSets.empty()); + TParentNodeSet *oldTopSet = mNodeSets.top(); + mNodeSets.pop(); - if (!nodeSets.empty()) { - TParentNodeSet* newTopSet = nodeSets.top(); + if (!mNodeSets.empty()) + { + TParentNodeSet *newTopSet = mNodeSets.top(); newTopSet->insert(oldTopSet->begin(), oldTopSet->end()); } @@ -76,106 +80,120 @@ private: // This can be called when there is no top set if we are visiting // symbols that are not under an assignment or condition. // We don't need to track those symbols. - void insertIntoTopSet(TGraphParentNode* node) + void insertIntoTopSet(TGraphParentNode *node) { - if (nodeSets.empty()) + if (mNodeSets.empty()) return; - nodeSets.top()->insert(node); + mNodeSets.top()->insert(node); } void clear() { - while (!nodeSets.empty()) + while (!mNodeSets.empty()) popSet(); } - private: - typedef std::stack TParentNodeSetStack; + private: + typedef std::stack TParentNodeSetStack; - TParentNodeSetStack nodeSets; + TParentNodeSetStack mNodeSets; }; // // An instance of this class pushes a new node set when instantiated. // When the instance goes out of scope, it and pops the node set. // - class TNodeSetMaintainer { - public: - TNodeSetMaintainer(TDependencyGraphBuilder* factory) - : sets(factory->mNodeSets) { sets.pushSet(); } - ~TNodeSetMaintainer() { sets.popSet(); } - protected: - TNodeSetStack& sets; + class TNodeSetMaintainer + { + public: + TNodeSetMaintainer(TDependencyGraphBuilder *factory) + : mSets(factory->mNodeSets) + { + mSets.pushSet(); + } + ~TNodeSetMaintainer() { mSets.popSet(); } + protected: + TNodeSetStack &mSets; }; // // An instance of this class pushes a new node set when instantiated. - // When the instance goes out of scope, it and pops the top node set and adds its contents to - // the new top node set. + // When the instance goes out of scope, it and pops the top node set and adds + // its contents to the new top node set. // - class TNodeSetPropagatingMaintainer { - public: - TNodeSetPropagatingMaintainer(TDependencyGraphBuilder* factory) - : sets(factory->mNodeSets) { sets.pushSet(); } - ~TNodeSetPropagatingMaintainer() { sets.popSetIntoNext(); } - protected: - TNodeSetStack& sets; + class TNodeSetPropagatingMaintainer + { + public: + TNodeSetPropagatingMaintainer(TDependencyGraphBuilder *factory) + : mSets(factory->mNodeSets) + { + mSets.pushSet(); + } + ~TNodeSetPropagatingMaintainer() { mSets.popSetIntoNext(); } + protected: + TNodeSetStack &mSets; }; // - // An instance of this class keeps track of the leftmost symbol while we're exploring an - // assignment. - // It will push the placeholder symbol kLeftSubtree when instantiated under a left subtree, - // and kRightSubtree under a right subtree. - // When it goes out of scope, it will pop the leftmost symbol at the top of the scope. - // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with a real symbol. - // kRightSubtree will never be replaced by a real symbol because we are tracking the leftmost - // symbol. + // An instance of this class keeps track of the leftmost symbol while we're + // exploring an assignment. + // It will push the placeholder symbol kLeftSubtree when instantiated under a + // left subtree, and kRightSubtree under a right subtree. + // When it goes out of scope, it will pop the leftmost symbol at the top of the + // scope. + // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with + // a real symbol. + // kRightSubtree will never be replaced by a real symbol because we are tracking + // the leftmost symbol. // - class TLeftmostSymbolMaintainer { - public: - TLeftmostSymbolMaintainer(TDependencyGraphBuilder* factory, TGraphSymbol& subtree) - : leftmostSymbols(factory->mLeftmostSymbols) + class TLeftmostSymbolMaintainer + { + public: + TLeftmostSymbolMaintainer( + TDependencyGraphBuilder *factory, TGraphSymbol &subtree) + : mLeftmostSymbols(factory->mLeftmostSymbols) { - needsPlaceholderSymbol = leftmostSymbols.empty() || leftmostSymbols.top() != &subtree; - if (needsPlaceholderSymbol) - leftmostSymbols.push(&subtree); + mNeedsPlaceholderSymbol = + mLeftmostSymbols.empty() || mLeftmostSymbols.top() != &subtree; + if (mNeedsPlaceholderSymbol) + mLeftmostSymbols.push(&subtree); } ~TLeftmostSymbolMaintainer() { - if (needsPlaceholderSymbol) - leftmostSymbols.pop(); + if (mNeedsPlaceholderSymbol) + mLeftmostSymbols.pop(); } - protected: - TSymbolStack& leftmostSymbols; - bool needsPlaceholderSymbol; + protected: + TSymbolStack& mLeftmostSymbols; + bool mNeedsPlaceholderSymbol; }; - TDependencyGraphBuilder(TDependencyGraph* graph) - : TIntermTraverser(true, false, false) - , mLeftSubtree(NULL) - , mRightSubtree(NULL) - , mGraph(graph) {} - void build(TIntermNode* intermNode) { intermNode->traverse(this); } + TDependencyGraphBuilder(TDependencyGraph *graph) + : TIntermTraverser(true, false, false), + mLeftSubtree(NULL), + mRightSubtree(NULL), + mGraph(graph) {} + void build(TIntermNode *intermNode) { intermNode->traverse(this); } - void connectMultipleNodesToSingleNode(TParentNodeSet* nodes, TGraphNode* node) const; + void connectMultipleNodesToSingleNode( + TParentNodeSet *nodes, TGraphNode *node) const; - void visitAssignment(TIntermBinary*); - void visitLogicalOp(TIntermBinary*); - void visitBinaryChildren(TIntermBinary*); - void visitFunctionDefinition(TIntermAggregate*); - void visitFunctionCall(TIntermAggregate* intermFunctionCall); - void visitAggregateChildren(TIntermAggregate*); + void visitAssignment(TIntermBinary *); + void visitLogicalOp(TIntermBinary *); + void visitBinaryChildren(TIntermBinary *); + void visitFunctionDefinition(TIntermAggregate *); + void visitFunctionCall(TIntermAggregate *intermFunctionCall); + void visitAggregateChildren(TIntermAggregate *); TGraphSymbol mLeftSubtree; TGraphSymbol mRightSubtree; - TDependencyGraph* mGraph; + TDependencyGraph *mGraph; TNodeSetStack mNodeSets; TSymbolStack mLeftmostSymbols; }; -#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H +#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.l b/src/3rdparty/angle/src/compiler/translator/glslang.l index ffc1aa18ac..518b78df11 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.l +++ b/src/3rdparty/angle/src/compiler/translator/glslang.l @@ -1,6 +1,6 @@ /* // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 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. // @@ -15,7 +15,7 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). %top{ // -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2013 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. // @@ -40,6 +40,7 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). #include "compiler/translator/ParseContext.h" #include "compiler/preprocessor/Token.h" #include "compiler/translator/util.h" +#include "compiler/translator/length_limits.h" #include "glslang_tab.h" /* windows only pragma */ @@ -57,8 +58,13 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner); static int check_type(yyscan_t yyscanner); static int reserved_word(yyscan_t yyscanner); +static int ES2_reserved_ES3_keyword(TParseContext *context, int token); +static int ES2_keyword_ES3_reserved(TParseContext *context, int token); +static int ES2_ident_ES3_keyword(TParseContext *context, int token); +static int uint_constant(TParseContext *context); static int int_constant(yyscan_t yyscanner); static int float_constant(yyscan_t yyscanner); +static int floatsuffix_check(TParseContext* context); %} %option noyywrap nounput never-interactive @@ -73,16 +79,20 @@ O [0-7] %% +%{ + TParseContext* context = yyextra; +%} + "invariant" { return INVARIANT; } "highp" { return HIGH_PRECISION; } "mediump" { return MEDIUM_PRECISION; } "lowp" { return LOW_PRECISION; } "precision" { return PRECISION; } -"attribute" { return ATTRIBUTE; } +"attribute" { return ES2_keyword_ES3_reserved(context, ATTRIBUTE); } "const" { return CONST_QUAL; } "uniform" { return UNIFORM; } -"varying" { return VARYING; } +"varying" { return ES2_keyword_ES3_reserved(context, VARYING); } "break" { return BREAK; } "continue" { return CONTINUE; } @@ -92,6 +102,13 @@ O [0-7] "if" { return IF; } "else" { return ELSE; } +"switch" { return ES2_reserved_ES3_keyword(context, SWITCH); } +"case" { return ES2_ident_ES3_keyword(context, CASE); } +"default" { return ES2_reserved_ES3_keyword(context, DEFAULT); } + +"centroid" { return ES2_ident_ES3_keyword(context, CENTROID); } +"flat" { return ES2_reserved_ES3_keyword(context, FLAT); } +"smooth" { return ES2_ident_ES3_keyword(context, SMOOTH); } "in" { return IN_QUAL; } "out" { return OUT_QUAL; } @@ -99,6 +116,7 @@ O [0-7] "float" { return FLOAT_TYPE; } "int" { return INT_TYPE; } +"uint" { return ES2_ident_ES3_keyword(context, UINT_TYPE); } "void" { return VOID_TYPE; } "bool" { return BOOL_TYPE; } "true" { yylval->lex.b = true; return BOOLCONSTANT; } @@ -111,6 +129,17 @@ O [0-7] "mat3" { return MATRIX3; } "mat4" { return MATRIX4; } +"mat2x2" { return ES2_ident_ES3_keyword(context, MATRIX2); } +"mat3x3" { return ES2_ident_ES3_keyword(context, MATRIX3); } +"mat4x4" { return ES2_ident_ES3_keyword(context, MATRIX4); } + +"mat2x3" { return ES2_ident_ES3_keyword(context, MATRIX2x3); } +"mat3x2" { return ES2_ident_ES3_keyword(context, MATRIX3x2); } +"mat2x4" { return ES2_ident_ES3_keyword(context, MATRIX2x4); } +"mat4x2" { return ES2_ident_ES3_keyword(context, MATRIX4x2); } +"mat3x4" { return ES2_ident_ES3_keyword(context, MATRIX3x4); } +"mat4x3" { return ES2_ident_ES3_keyword(context, MATRIX4x3); } + "vec2" { return VEC2; } "vec3" { return VEC3; } "vec4" { return VEC4; } @@ -120,70 +149,160 @@ O [0-7] "bvec2" { return BVEC2; } "bvec3" { return BVEC3; } "bvec4" { return BVEC4; } - -"sampler2D" { return SAMPLER2D; } -"samplerCube" { return SAMPLERCUBE; } -"samplerExternalOES" { return SAMPLER_EXTERNAL_OES; } -"sampler2DRect" { return SAMPLER2DRECT; } +"uvec2" { return ES2_ident_ES3_keyword(context, UVEC2); } +"uvec3" { return ES2_ident_ES3_keyword(context, UVEC3); } +"uvec4" { return ES2_ident_ES3_keyword(context, UVEC4); } + +"sampler2D" { return SAMPLER2D; } +"samplerCube" { return SAMPLERCUBE; } +"samplerExternalOES" { return SAMPLER_EXTERNAL_OES; } +"sampler3D" { return ES2_reserved_ES3_keyword(context, SAMPLER3D); } +"sampler3DRect" { return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); } +"sampler2DRect" { return SAMPLER2DRECT; } +"sampler2DArray" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); } +"isampler2D" { return ES2_ident_ES3_keyword(context, ISAMPLER2D); } +"isampler3D" { return ES2_ident_ES3_keyword(context, ISAMPLER3D); } +"isamplerCube" { return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); } +"isampler2DArray" { return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); } +"usampler2D" { return ES2_ident_ES3_keyword(context, USAMPLER2D); } +"usampler3D" { return ES2_ident_ES3_keyword(context, USAMPLER3D); } +"usamplerCube" { return ES2_ident_ES3_keyword(context, USAMPLERCUBE); } +"usampler2DArray" { return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); } +"sampler2DShadow" { return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); } +"samplerCubeShadow" { return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); } +"sampler2DArrayShadow" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); } "struct" { return STRUCT; } -"asm" { return reserved_word(yyscanner); } - -"class" { return reserved_word(yyscanner); } -"union" { return reserved_word(yyscanner); } -"enum" { return reserved_word(yyscanner); } -"typedef" { return reserved_word(yyscanner); } -"template" { return reserved_word(yyscanner); } -"this" { return reserved_word(yyscanner); } -"packed" { return reserved_word(yyscanner); } - -"goto" { return reserved_word(yyscanner); } -"switch" { return reserved_word(yyscanner); } -"default" { return reserved_word(yyscanner); } - -"inline" { return reserved_word(yyscanner); } -"noinline" { return reserved_word(yyscanner); } -"volatile" { return reserved_word(yyscanner); } -"public" { return reserved_word(yyscanner); } -"static" { return reserved_word(yyscanner); } -"extern" { return reserved_word(yyscanner); } -"external" { return reserved_word(yyscanner); } -"interface" { return reserved_word(yyscanner); } -"flat" { return reserved_word(yyscanner); } - -"long" { return reserved_word(yyscanner); } -"short" { return reserved_word(yyscanner); } -"double" { return reserved_word(yyscanner); } -"half" { return reserved_word(yyscanner); } -"fixed" { return reserved_word(yyscanner); } -"unsigned" { return reserved_word(yyscanner); } -"superp" { return reserved_word(yyscanner); } - -"input" { return reserved_word(yyscanner); } -"output" { return reserved_word(yyscanner); } - -"hvec2" { return reserved_word(yyscanner); } -"hvec3" { return reserved_word(yyscanner); } -"hvec4" { return reserved_word(yyscanner); } -"dvec2" { return reserved_word(yyscanner); } -"dvec3" { return reserved_word(yyscanner); } -"dvec4" { return reserved_word(yyscanner); } -"fvec2" { return reserved_word(yyscanner); } -"fvec3" { return reserved_word(yyscanner); } -"fvec4" { return reserved_word(yyscanner); } - -"sampler1D" { return reserved_word(yyscanner); } -"sampler3D" { return reserved_word(yyscanner); } -"sampler1DShadow" { return reserved_word(yyscanner); } -"sampler2DShadow" { return reserved_word(yyscanner); } -"sampler3DRect" { return reserved_word(yyscanner); } -"sampler2DRectShadow" { return reserved_word(yyscanner); } - -"sizeof" { return reserved_word(yyscanner); } -"cast" { return reserved_word(yyscanner); } - -"namespace" { return reserved_word(yyscanner); } +"layout" { return ES2_ident_ES3_keyword(context, LAYOUT); } + + /* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */ +"coherent" | +"restrict" | +"readonly" | +"writeonly" | +"resource" | +"atomic_uint" | +"noperspective" | +"patch" | +"sample" | +"subroutine" | +"common" | +"partition" | +"active" | + +"filter" | +"image1D" | +"image2D" | +"image3D" | +"imageCube" | +"iimage1D" | +"iimage2D" | +"iimage3D" | +"iimageCube" | +"uimage1D" | +"uimage2D" | +"uimage3D" | +"uimageCube" | +"image1DArray" | +"image2DArray" | +"iimage1DArray" | +"iimage2DArray" | +"uimage1DArray" | +"uimage2DArray" | +"image1DShadow" | +"image2DShadow" | +"image1DArrayShadow" | +"image2DArrayShadow" | +"imageBuffer" | +"iimageBuffer" | +"uimageBuffer" | + +"sampler1DArray" | +"sampler1DArrayShadow" | +"isampler1D" | +"isampler1DArray" | +"usampler1D" | +"usampler1DArray" | +"isampler2DRect" | +"usampler2DRect" | +"samplerBuffer" | +"isamplerBuffer" | +"usamplerBuffer" | +"sampler2DMS" | +"isampler2DMS" | +"usampler2DMS" | +"sampler2DMSArray" | +"isampler2DMSArray" | +"usampler2DMSArray" { + if (context->shaderVersion < 300) { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + return reserved_word(yyscanner); +} + + /* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */ +"packed" { + if (context->shaderVersion >= 300) + { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + + return reserved_word(yyscanner); +} + + /* Reserved keywords */ +"asm" | + +"class" | +"union" | +"enum" | +"typedef" | +"template" | +"this" | + +"goto" | + +"inline" | +"noinline" | +"volatile" | +"public" | +"static" | +"extern" | +"external" | +"interface" | + +"long" | +"short" | +"double" | +"half" | +"fixed" | +"unsigned" | +"superp" | + +"input" | +"output" | + +"hvec2" | +"hvec3" | +"hvec4" | +"dvec2" | +"dvec3" | +"dvec4" | +"fvec2" | +"fvec3" | +"fvec4" | + +"sampler1D" | +"sampler1DShadow" | +"sampler2DRectShadow" | + +"sizeof" | +"cast" | + +"namespace" | "using" { return reserved_word(yyscanner); } {L}({L}|{D})* { @@ -195,10 +314,18 @@ O [0-7] 0{O}+ { return int_constant(yyscanner); } {D}+ { return int_constant(yyscanner); } +0[xX]{H}+[uU] { return uint_constant(context); } +0{O}+[uU] { return uint_constant(context); } +{D}+[uU] { return uint_constant(context); } + {D}+{E} { return float_constant(yyscanner); } {D}+"."{D}*({E})? { return float_constant(yyscanner); } "."{D}+({E})? { return float_constant(yyscanner); } +{D}+{E}[fF] { return floatsuffix_check(context); } +{D}+"."{D}*({E})?[fF] { return floatsuffix_check(context); } +"."{D}+({E})?[fF] { return floatsuffix_check(context); } + "+=" { return ADD_ASSIGN; } "-=" { return SUB_ASSIGN; } "*=" { return MUL_ASSIGN; } @@ -224,31 +351,31 @@ O [0-7] ";" { return SEMICOLON; } ("{"|"<%") { return LEFT_BRACE; } ("}"|"%>") { return RIGHT_BRACE; } -"," { return COMMA; } -":" { return COLON; } -"=" { return EQUAL; } -"(" { return LEFT_PAREN; } -")" { return RIGHT_PAREN; } -("["|"<:") { return LEFT_BRACKET; } -("]"|":>") { return RIGHT_BRACKET; } -"." { return DOT; } -"!" { return BANG; } -"-" { return DASH; } -"~" { return TILDE; } -"+" { return PLUS; } -"*" { return STAR; } -"/" { return SLASH; } -"%" { return PERCENT; } -"<" { return LEFT_ANGLE; } -">" { return RIGHT_ANGLE; } -"|" { return VERTICAL_BAR; } -"^" { return CARET; } -"&" { return AMPERSAND; } -"?" { return QUESTION; } +"," { return COMMA; } +":" { return COLON; } +"=" { return EQUAL; } +"(" { return LEFT_PAREN; } +")" { return RIGHT_PAREN; } +("["|"<:") { return LEFT_BRACKET; } +("]"|":>") { return RIGHT_BRACKET; } +"." { return DOT; } +"!" { return BANG; } +"-" { return DASH; } +"~" { return TILDE; } +"+" { return PLUS; } +"*" { return STAR; } +"/" { return SLASH; } +"%" { return PERCENT; } +"<" { return LEFT_ANGLE; } +">" { return RIGHT_ANGLE; } +"|" { return VERTICAL_BAR; } +"^" { return CARET; } +"&" { return AMPERSAND; } +"?" { return QUESTION; } [ \t\v\n\f\r] { } -<> { yyterminate(); } -. { assert(false); return 0; } +<> { yyterminate(); } +. { assert(false); return 0; } %% @@ -272,11 +399,12 @@ int check_type(yyscan_t yyscanner) { struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; int token = IDENTIFIER; - TSymbol* symbol = yyextra->symbolTable.find(yytext); + TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->shaderVersion); if (symbol && symbol->isVariable()) { TVariable* variable = static_cast(symbol); - if (variable->isUserType()) + if (variable->isUserType()) { token = TYPE_NAME; + } } yylval->lex.symbol = symbol; return token; @@ -290,6 +418,80 @@ int reserved_word(yyscan_t yyscanner) { return 0; } +int ES2_reserved_ES3_keyword(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->scanner; + + if (context->shaderVersion < 300) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_keyword_ES3_reserved(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->scanner; + + if (context->shaderVersion >= 300) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_ident_ES3_keyword(TParseContext *context, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + yyscan_t yyscanner = (yyscan_t) context->scanner; + + // not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name + if (context->shaderVersion < 300) + { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + + return token; +} + +int uint_constant(TParseContext *context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + yyscan_t yyscanner = (yyscan_t) context->scanner; + + if (context->shaderVersion < 300) + { + context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, ""); + context->recover(); + return 0; + } + + if (!atoi_clamp(yytext, &(yylval->lex.i))) + yyextra->warning(*yylloc, "Integer overflow", yytext, ""); + + return UINTCONSTANT; +} + +int floatsuffix_check(TParseContext* context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + + if (context->shaderVersion < 300) + { + context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext); + context->recover(); + return 0; + } + + if (!atof_clamp(yytext, &(yylval->lex.f))) + yyextra->warning(*yylloc, "Float overflow", yytext, ""); + + return(FLOATCONSTANT); +} + void yyerror(YYLTYPE* lloc, TParseContext* context, const char* reason) { context->error(*lloc, reason, yyget_text(context->scanner)); context->recover(); @@ -339,7 +541,6 @@ int glslang_scan(size_t count, const char* const string[], const int length[], // Initialize preprocessor. if (!context->preprocessor.init(count, string, length)) return 1; - context->preprocessor.setMaxTokenLength(SH_MAX_TOKEN_LENGTH); // Define extension macros. const TExtensionBehavior& extBehavior = context->extensionBehavior(); @@ -350,6 +551,8 @@ int glslang_scan(size_t count, const char* const string[], const int length[], if (context->fragmentPrecisionHigh) context->preprocessor.predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1); + context->preprocessor.setMaxTokenSize(GetGlobalMaxTokenSize(context->shaderSpec)); + return 0; } diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.y b/src/3rdparty/angle/src/compiler/translator/glslang.y index 7614ff3447..fb2d835368 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.y +++ b/src/3rdparty/angle/src/compiler/translator/glslang.y @@ -1,6 +1,6 @@ /* // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -15,7 +15,7 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). %{ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -34,6 +34,7 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). #pragma warning(disable: 4701) #endif +#include "angle_gl.h" #include "compiler/translator/SymbolTable.h" #include "compiler/translator/ParseContext.h" #include "GLSLANG/ShaderLang.h" @@ -41,8 +42,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). #define YYENABLE_NLS 0 #define YYLEX_PARAM context->scanner -%} +%} %expect 1 /* One shift reduce conflict because of if | else */ %pure-parser %parse-param {TParseContext* context} @@ -51,7 +52,6 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). %code requires { #define YYLTYPE TSourceLoc #define YYLTYPE_IS_DECLARED 1 -#define SH_MAX_TOKEN_LENGTH 256 // WebGL spec. } %union { @@ -60,6 +60,7 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). TString *string; float f; int i; + unsigned int u; bool b; }; TSymbol* symbol; @@ -75,6 +76,7 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). union { TPublicType type; TPrecision precision; + TLayoutQualifier layoutQualifier; TQualifier qualifier; TFunction* function; TParameter param; @@ -105,29 +107,50 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason) } while (0) #define VERTEX_ONLY(S, L) { \ - if (context->shaderType != SH_VERTEX_SHADER) { \ + if (context->shaderType != GL_VERTEX_SHADER) { \ context->error(L, " supported in vertex shaders only ", S); \ context->recover(); \ } \ } #define FRAG_ONLY(S, L) { \ - if (context->shaderType != SH_FRAGMENT_SHADER) { \ + if (context->shaderType != GL_FRAGMENT_SHADER) { \ context->error(L, " supported in fragment shaders only ", S); \ context->recover(); \ } \ } + +#define ES2_ONLY(S, L) { \ + if (context->shaderVersion != 100) { \ + context->error(L, " supported in GLSL ES 1.00 only ", S); \ + context->recover(); \ + } \ +} + +#define ES3_ONLY(TOKEN, LINE, REASON) { \ + if (context->shaderVersion != 300) { \ + context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \ + context->recover(); \ + } \ +} %} %token INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION -%token ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE -%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN -%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 +%token ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE UINT_TYPE +%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT +%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 UVEC2 UVEC3 UVEC4 %token MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING +%token MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3 +%token CENTROID FLAT SMOOTH %token STRUCT VOID_TYPE WHILE -%token SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT - -%token IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT BOOLCONSTANT +%token SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY +%token ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY +%token USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY +%token SAMPLER3D SAMPLER3DRECT SAMPLER2DSHADOW SAMPLERCUBESHADOW SAMPLER2DARRAYSHADOW +%token LAYOUT + +%token IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT +%token FIELD_SELECTION %token LEFT_OP RIGHT_OP %token INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP %token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN @@ -160,10 +183,11 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason) %type single_declaration init_declarator_list %type parameter_declaration parameter_declarator parameter_type_specifier -%type parameter_qualifier +%type parameter_qualifier parameter_type_qualifier +%type layout_qualifier layout_qualifier_id_list layout_qualifier_id %type precision_qualifier -%type type_qualifier fully_specified_type type_specifier +%type type_qualifier fully_specified_type type_specifier storage_qualifier interpolation_qualifier %type type_specifier_no_prec type_specifier_nonarray %type struct_specifier %type struct_declarator @@ -173,6 +197,8 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason) %type function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype %type function_call_or_method +%type enter_struct + %start translation_unit %% @@ -200,7 +226,7 @@ variable_identifier { variable = static_cast(symbol); - if (context->symbolTable.findBuiltIn(variable->getName()) && + if (context->symbolTable.findBuiltIn(variable->getName(), context->shaderVersion) && !variable->getExtension().empty() && context->extensionErrorCheck(@1, variable->getExtension())) { @@ -212,7 +238,7 @@ variable_identifier { TType type(EbtFloat, EbpUndefined); TVariable *fakeVariable = new TVariable($1.string, type); - context->symbolTable.insert(*fakeVariable); + context->symbolTable.declare(fakeVariable); variable = fakeVariable; } @@ -244,6 +270,11 @@ primary_expression unionArray->setIConst($1.i); $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @1); } + | UINTCONSTANT { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setUConst($1.u); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), @1); + } | FLOATCONSTANT { ConstantUnion *unionArray = new ConstantUnion[1]; unionArray->setFConst($1.f); @@ -270,104 +301,12 @@ postfix_expression $$ = $1; } | postfix_expression DOT identifier { - if ($1->isArray()) { - context->error(@3, "cannot apply dot operator to an array", "."); - context->recover(); - } - - if ($1->isVector()) { - TVectorFields fields; - if (! context->parseVectorFields(*$3.string, $1->getNominalSize(), fields, @3)) { - fields.num = 1; - fields.offsets[0] = 0; - context->recover(); - } - - if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields - $$ = context->addConstVectorNode(fields, $1, @3); - if ($$ == 0) { - context->recover(); - $$ = $1; - } - else - $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, (int) (*$3.string).size())); - } else { - TString vectorString = *$3.string; - TIntermTyped* index = context->intermediate.addSwizzle(fields, @3); - $$ = context->intermediate.addIndex(EOpVectorSwizzle, $1, index, @2); - $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, (int) vectorString.size())); - } - } else if ($1->isMatrix()) { - TMatrixFields fields; - if (! context->parseMatrixFields(*$3.string, $1->getNominalSize(), fields, @3)) { - fields.wholeRow = false; - fields.wholeCol = false; - fields.row = 0; - fields.col = 0; - context->recover(); - } - - if (fields.wholeRow || fields.wholeCol) { - context->error(@2, " non-scalar fields not implemented yet", "."); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setIConst(0); - TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @3); - $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, @2); - $$->setType(TType($1->getBasicType(), $1->getPrecision(),EvqTemporary, $1->getNominalSize())); - } else { - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row); - TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @3); - $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, @2); - $$->setType(TType($1->getBasicType(), $1->getPrecision())); - } - } else if ($1->getBasicType() == EbtStruct) { - bool fieldFound = false; - const TFieldList& fields = $1->getType().getStruct()->fields(); - unsigned int i; - for (i = 0; i < fields.size(); ++i) { - if (fields[i]->name() == *$3.string) { - fieldFound = true; - break; - } - } - if (fieldFound) { - if ($1->getType().getQualifier() == EvqConst) { - $$ = context->addConstStruct(*$3.string, $1, @2); - if ($$ == 0) { - context->recover(); - $$ = $1; - } - else { - $$->setType(*fields[i]->type()); - // change the qualifier of the return type, not of the structure field - // as the structure definition is shared between various structures. - $$->getTypePointer()->setQualifier(EvqConst); - } - } else { - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setIConst(i); - TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *fields[i]->type(), @3); - $$ = context->intermediate.addIndex(EOpIndexDirectStruct, $1, index, @2); - $$->setType(*fields[i]->type()); - } - } else { - context->error(@2, " no such field in structure", $3.string->c_str()); - context->recover(); - $$ = $1; - } - } else { - context->error(@2, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str()); - context->recover(); - $$ = $1; - } - // don't delete $3.string, it's from the pool + $$ = context->addFieldSelectionExpression($1, @2, *$3.string, @3); } | postfix_expression INC_OP { if (context->lValueErrorCheck(@2, "++", $1)) context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, @2, context->symbolTable); + $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, @2); if ($$ == 0) { context->unaryOpError(@2, "++", $1->getCompleteString()); context->recover(); @@ -377,7 +316,7 @@ postfix_expression | postfix_expression DEC_OP { if (context->lValueErrorCheck(@2, "--", $1)) context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, @2, context->symbolTable); + $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, @2); if ($$ == 0) { context->unaryOpError(@2, "--", $1->getCompleteString()); context->recover(); @@ -427,7 +366,7 @@ function_call // const TFunction* fnCandidate; bool builtIn; - fnCandidate = context->findFunction(@1, fnCall, &builtIn); + fnCandidate = context->findFunction(@1, fnCall, context->shaderVersion, &builtIn); if (fnCandidate) { // // A declared function. @@ -445,7 +384,7 @@ function_call // // Treat it like a built-in unary operator. // - $$ = context->intermediate.addUnaryMath(op, $1.intermNode, @1, context->symbolTable); + $$ = context->intermediate.addUnaryMath(op, $1.intermNode, @1); if ($$ == 0) { std::stringstream extraInfoStream; extraInfoStream << "built in unary operator function. Type: " << static_cast($1.intermNode)->getCompleteString(); @@ -473,7 +412,7 @@ function_call for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) { qual = fnCandidate->getParam(i).type->getQualifier(); if (qual == EvqOut || qual == EvqInOut) { - if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) { + if (context->lValueErrorCheck($$->getLine(), "assign", (*($$->getAsAggregate()->getSequence()))[i]->getAsTyped())) { context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); context->recover(); } @@ -550,59 +489,7 @@ function_call_header function_identifier : type_specifier_nonarray { - // - // Constructor - // - TOperator op = EOpNull; - if ($1.userDef) { - op = EOpConstructStruct; - } else { - switch ($1.type) { - case EbtFloat: - if ($1.matrix) { - switch($1.size) { - case 2: op = EOpConstructMat2; break; - case 3: op = EOpConstructMat3; break; - case 4: op = EOpConstructMat4; break; - } - } else { - switch($1.size) { - case 1: op = EOpConstructFloat; break; - case 2: op = EOpConstructVec2; break; - case 3: op = EOpConstructVec3; break; - case 4: op = EOpConstructVec4; break; - } - } - break; - case EbtInt: - switch($1.size) { - case 1: op = EOpConstructInt; break; - case 2: op = EOpConstructIVec2; break; - case 3: op = EOpConstructIVec3; break; - case 4: op = EOpConstructIVec4; break; - } - break; - case EbtBool: - switch($1.size) { - case 1: op = EOpConstructBool; break; - case 2: op = EOpConstructBVec2; break; - case 3: op = EOpConstructBVec3; break; - case 4: op = EOpConstructBVec4; break; - } - break; - default: break; - } - if (op == EOpNull) { - context->error(@1, "cannot construct this type", getBasicString($1.type)); - context->recover(); - $1.type = EbtFloat; - op = EOpConstructFloat; - } - } - TString tempString; - TType type($1); - TFunction *function = new TFunction(&tempString, type, op); - $$ = function; + $$ = context->addConstructorFunc($1); } | IDENTIFIER { if (context->reservedErrorCheck(@1, *$1.string)) @@ -620,7 +507,7 @@ unary_expression | INC_OP unary_expression { if (context->lValueErrorCheck(@1, "++", $2)) context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, @1, context->symbolTable); + $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, @1); if ($$ == 0) { context->unaryOpError(@1, "++", $2->getCompleteString()); context->recover(); @@ -630,7 +517,7 @@ unary_expression | DEC_OP unary_expression { if (context->lValueErrorCheck(@1, "--", $2)) context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, @1, context->symbolTable); + $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, @1); if ($$ == 0) { context->unaryOpError(@1, "--", $2->getCompleteString()); context->recover(); @@ -639,7 +526,7 @@ unary_expression } | unary_operator unary_expression { if ($1.op != EOpNull) { - $$ = context->intermediate.addUnaryMath($1.op, $2, @1, context->symbolTable); + $$ = context->intermediate.addUnaryMath($1.op, $2, @1); if ($$ == 0) { const char* errorOp = ""; switch($1.op) { @@ -667,7 +554,7 @@ unary_operator multiplicative_expression : unary_expression { $$ = $1; } | multiplicative_expression STAR unary_expression { - $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "*", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -675,7 +562,7 @@ multiplicative_expression } } | multiplicative_expression SLASH unary_expression { - $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "/", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -687,7 +574,7 @@ multiplicative_expression additive_expression : multiplicative_expression { $$ = $1; } | additive_expression PLUS multiplicative_expression { - $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "+", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -695,7 +582,7 @@ additive_expression } } | additive_expression DASH multiplicative_expression { - $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "-", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -711,7 +598,7 @@ shift_expression relational_expression : shift_expression { $$ = $1; } | relational_expression LEFT_ANGLE shift_expression { - $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "<", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -721,7 +608,7 @@ relational_expression } } | relational_expression RIGHT_ANGLE shift_expression { - $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, ">", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -731,7 +618,7 @@ relational_expression } } | relational_expression LE_OP shift_expression { - $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "<=", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -741,7 +628,7 @@ relational_expression } } | relational_expression GE_OP shift_expression { - $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, ">=", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -755,7 +642,7 @@ relational_expression equality_expression : relational_expression { $$ = $1; } | equality_expression EQ_OP relational_expression { - $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "==", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -765,7 +652,7 @@ equality_expression } } | equality_expression NE_OP relational_expression { - $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "!=", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -791,7 +678,7 @@ inclusive_or_expression logical_and_expression : inclusive_or_expression { $$ = $1; } | logical_and_expression AND_OP inclusive_or_expression { - $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "&&", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -805,7 +692,7 @@ logical_and_expression logical_xor_expression : logical_and_expression { $$ = $1; } | logical_xor_expression XOR_OP logical_and_expression { - $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "^^", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -819,7 +706,7 @@ logical_xor_expression logical_or_expression : logical_xor_expression { $$ = $1; } | logical_or_expression OR_OP logical_xor_expression { - $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, @2, context->symbolTable); + $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, @2); if ($$ == 0) { context->binaryOpError(@2, "||", $1->getCompleteString(), $3->getCompleteString()); context->recover(); @@ -892,6 +779,14 @@ constant_expression } ; +enter_struct + : IDENTIFIER LEFT_BRACE { + if (context->enterStructDeclaration(@1, *$1.string)) + context->recover(); + $$ = $1; + } + ; + declaration : function_prototype SEMICOLON { TFunction &function = *($1.function); @@ -926,7 +821,7 @@ declaration $$ = $1.intermAggregate; } | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON { - if (($2 == EbpHigh) && (context->shaderType == SH_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) { + if (($2 == EbpHigh) && (context->shaderType == GL_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) { context->error(@1, "precision is not supported in fragment shader", "highp"); context->recover(); } @@ -936,6 +831,22 @@ declaration } $$ = 0; } + | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON { + ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); + $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @$, NULL, @$); + } + | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON { + ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); + $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @$); + } + | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON { + ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); + $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6); + } + | type_qualifier SEMICOLON { + context->parseGlobalLayoutQualifier($1); + $$ = 0; + } ; function_prototype @@ -948,7 +859,7 @@ function_prototype // // Redeclarations are allowed. But, return types and parameter qualifiers must match. // - TFunction* prevDec = static_cast(context->symbolTable.find($1->getMangledName())); + TFunction* prevDec = static_cast(context->symbolTable.find($1->getMangledName(), context->shaderVersion)); if (prevDec) { if (prevDec->getReturnType() != $1->getReturnType()) { context->error(@2, "overloaded functions must have the same return type", $1->getReturnType().getBasicString()); @@ -965,7 +876,7 @@ function_prototype // // Check for previously declared variables using the same name. // - TSymbol *prevSym = context->symbolTable.find($1->getName()); + TSymbol *prevSym = context->symbolTable.find($1->getName(), context->shaderVersion); if (prevSym) { if (!prevSym->isFunction()) @@ -977,7 +888,8 @@ function_prototype else { // Insert the unmangled name to detect potential future redefinition as a variable. - context->symbolTable.getOuterLevel()->insert($1->getName(), *$1); + TFunction *function = new TFunction(NewPoolTString($1->getName().c_str()), $1->getReturnType()); + context->symbolTable.getOuterLevel()->insert(function); } // @@ -989,7 +901,7 @@ function_prototype // We're at the inner scope level of the function's arguments and body statement. // Add the function prototype to the surrounding scope instead. - context->symbolTable.getOuterLevel()->insert(*$$.function); + context->symbolTable.getOuterLevel()->insert($$.function); } ; @@ -1092,9 +1004,9 @@ parameter_declaration // // Type + name // - : type_qualifier parameter_qualifier parameter_declarator { + : parameter_type_qualifier parameter_qualifier parameter_declarator { $$ = $3; - if (context->paramErrorCheck(@3, $1.qualifier, $2, $$.param.type)) + if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) context->recover(); } | parameter_qualifier parameter_declarator { @@ -1107,9 +1019,9 @@ parameter_declaration // // Only type // - | type_qualifier parameter_qualifier parameter_type_specifier { + | parameter_type_qualifier parameter_qualifier parameter_type_specifier { $$ = $3; - if (context->paramErrorCheck(@3, $1.qualifier, $2, $$.param.type)) + if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) context->recover(); } | parameter_qualifier parameter_type_specifier { @@ -1148,173 +1060,46 @@ init_declarator_list $$ = $1; } | init_declarator_list COMMA identifier { - if ($1.type.type == EbtInvariant && !$3.symbol) - { - context->error(@3, "undeclared identifier declared as invariant", $3.string->c_str()); - context->recover(); - } - - TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$3.string, TType($1.type), @3); - $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, symbol, @3); - - if (context->structQualifierErrorCheck(@3, $$.type)) - context->recover(); - - if (context->nonInitConstErrorCheck(@3, *$3.string, $$.type, false)) - context->recover(); - - TVariable* variable = 0; - if (context->nonInitErrorCheck(@3, *$3.string, $$.type, variable)) - context->recover(); - if (symbol && variable) - symbol->setId(variable->getUniqueId()); + $$ = $1; + $$.intermAggregate = context->parseDeclarator($$.type, $1.intermAggregate, $3.symbol, @3, *$3.string); } | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET { - if (context->structQualifierErrorCheck(@3, $1.type)) - context->recover(); - - if (context->nonInitConstErrorCheck(@3, *$3.string, $1.type, true)) - context->recover(); - $$ = $1; - - if (context->arrayTypeErrorCheck(@4, $1.type) || context->arrayQualifierErrorCheck(@4, $1.type)) - context->recover(); - else { - $1.type.setArray(true); - TVariable* variable; - if (context->arrayErrorCheck(@4, *$3.string, $1.type, variable)) - context->recover(); - } + context->parseArrayDeclarator($$.type, @3, *$3.string, @4, NULL, NULL); } | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { - if (context->structQualifierErrorCheck(@3, $1.type)) - context->recover(); - - if (context->nonInitConstErrorCheck(@3, *$3.string, $1.type, true)) - context->recover(); - $$ = $1; - - if (context->arrayTypeErrorCheck(@4, $1.type) || context->arrayQualifierErrorCheck(@4, $1.type)) - context->recover(); - else { - int size; - if (context->arraySizeErrorCheck(@4, $5, size)) - context->recover(); - $1.type.setArray(true, size); - TVariable* variable = 0; - if (context->arrayErrorCheck(@4, *$3.string, $1.type, variable)) - context->recover(); - TType type = TType($1.type); - type.setArraySize(size); - $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *$3.string, type, @3), @3); - } + $$.intermAggregate = context->parseArrayDeclarator($$.type, @3, *$3.string, @4, $1.intermNode, $5); } | init_declarator_list COMMA identifier EQUAL initializer { - if (context->structQualifierErrorCheck(@3, $1.type)) - context->recover(); - $$ = $1; - - TIntermNode* intermNode; - if (!context->executeInitializer(@3, *$3.string, $1.type, $5, intermNode)) { - // - // build the intermediate representation - // - if (intermNode) - $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, intermNode, @4); - else - $$.intermAggregate = $1.intermAggregate; - } else { - context->recover(); - $$.intermAggregate = 0; - } + $$.intermAggregate = context->parseInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5); } ; single_declaration : fully_specified_type { $$.type = $1; - $$.intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType($1), @1), @1); + $$.intermAggregate = context->parseSingleDeclaration($$.type, @1, ""); } | fully_specified_type identifier { - TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), @2); - $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2); - - if (context->structQualifierErrorCheck(@2, $$.type)) - context->recover(); - - if (context->nonInitConstErrorCheck(@2, *$2.string, $$.type, false)) - context->recover(); - - $$.type = $1; - - TVariable* variable = 0; - if (context->nonInitErrorCheck(@2, *$2.string, $$.type, variable)) - context->recover(); - if (variable && symbol) - symbol->setId(variable->getUniqueId()); + $$.type = $1; + $$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string); } | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET { context->error(@2, "unsized array declarations not supported", $2.string->c_str()); context->recover(); - TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), @2); - $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2); $$.type = $1; + $$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string); } | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { - TType type = TType($1); - int size; - if (context->arraySizeErrorCheck(@2, $4, size)) - context->recover(); - type.setArraySize(size); - TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, type, @2); - $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2); - - if (context->structQualifierErrorCheck(@2, $1)) - context->recover(); - - if (context->nonInitConstErrorCheck(@2, *$2.string, $1, true)) - context->recover(); - $$.type = $1; - - if (context->arrayTypeErrorCheck(@3, $1) || context->arrayQualifierErrorCheck(@3, $1)) - context->recover(); - else { - int size; - if (context->arraySizeErrorCheck(@3, $4, size)) - context->recover(); - - $1.setArray(true, size); - TVariable* variable = 0; - if (context->arrayErrorCheck(@3, *$2.string, $1, variable)) - context->recover(); - if (variable && symbol) - symbol->setId(variable->getUniqueId()); - } + $$.intermAggregate = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4); } | fully_specified_type identifier EQUAL initializer { - if (context->structQualifierErrorCheck(@2, $1)) - context->recover(); - $$.type = $1; - - TIntermNode* intermNode; - if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode)) { - // - // Build intermediate representation - // - if(intermNode) - $$.intermAggregate = context->intermediate.makeAggregate(intermNode, @3); - else - $$.intermAggregate = 0; - } else { - context->recover(); - $$.intermAggregate = 0; - } + $$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4); } | INVARIANT IDENTIFIER { VERTEX_ONLY("invariant declaration", @1); @@ -1347,57 +1132,113 @@ fully_specified_type } } | type_qualifier type_specifier { - if ($2.array) { - context->error(@2, "not supported", "first-class array"); - context->recover(); - $2.setArray(false); - } + $$ = context->addFullySpecifiedType($1.qualifier, $1.layoutQualifier, $2); + } + ; - if ($1.qualifier == EvqAttribute && - ($2.type == EbtBool || $2.type == EbtInt)) { - context->error(@2, "cannot be bool or int", getQualifierString($1.qualifier)); - context->recover(); - } - if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) && - ($2.type == EbtBool || $2.type == EbtInt)) { - context->error(@2, "cannot be bool or int", getQualifierString($1.qualifier)); - context->recover(); - } - $$ = $2; - $$.qualifier = $1.qualifier; +interpolation_qualifier + : SMOOTH { + $$.qualifier = EvqSmooth; + } + | FLAT { + $$.qualifier = EvqFlat; } ; -type_qualifier +parameter_type_qualifier : CONST_QUAL { - $$.setBasic(EbtVoid, EvqConst, @1); + $$ = EvqConst; } - | ATTRIBUTE { + ; + +type_qualifier + : ATTRIBUTE { VERTEX_ONLY("attribute", @1); + ES2_ONLY("attribute", @1); if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "attribute")) context->recover(); $$.setBasic(EbtVoid, EvqAttribute, @1); } | VARYING { + ES2_ONLY("varying", @1); if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "varying")) context->recover(); - if (context->shaderType == SH_VERTEX_SHADER) + if (context->shaderType == GL_VERTEX_SHADER) $$.setBasic(EbtVoid, EvqVaryingOut, @1); else $$.setBasic(EbtVoid, EvqVaryingIn, @1); } | INVARIANT VARYING { + ES2_ONLY("varying", @1); if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying")) context->recover(); - if (context->shaderType == SH_VERTEX_SHADER) + if (context->shaderType == GL_VERTEX_SHADER) $$.setBasic(EbtVoid, EvqInvariantVaryingOut, @1); else $$.setBasic(EbtVoid, EvqInvariantVaryingIn, @1); } + | storage_qualifier { + if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) { + context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1.qualifier)); + context->recover(); + } else { + $$.setBasic(EbtVoid, $1.qualifier, @1); + } + } + | interpolation_qualifier storage_qualifier { + $$ = context->joinInterpolationQualifiers(@1, $1.qualifier, @2, $2.qualifier); + } + | interpolation_qualifier { + context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString($1.qualifier)); + context->recover(); + + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtVoid, qual, @1); + } + | layout_qualifier { + $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.layoutQualifier = $1; + } + | layout_qualifier storage_qualifier { + $$.setBasic(EbtVoid, $2.qualifier, @2); + $$.layoutQualifier = $1; + } + ; + +storage_qualifier + : CONST_QUAL { + $$.qualifier = EvqConst; + } + | IN_QUAL { + ES3_ONLY("in", @1, "storage qualifier"); + $$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn; + } + | OUT_QUAL { + ES3_ONLY("out", @1, "storage qualifier"); + $$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut; + } + | CENTROID IN_QUAL { + ES3_ONLY("centroid in", @1, "storage qualifier"); + if (context->shaderType == GL_VERTEX_SHADER) + { + context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader"); + context->recover(); + } + $$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn; + } + | CENTROID OUT_QUAL { + ES3_ONLY("centroid out", @1, "storage qualifier"); + if (context->shaderType == GL_FRAGMENT_SHADER) + { + context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader"); + context->recover(); + } + $$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut; + } | UNIFORM { if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform")) context->recover(); - $$.setBasic(EbtVoid, EvqUniform, @1); + $$.qualifier = EvqUniform; } ; @@ -1415,6 +1256,11 @@ type_specifier | precision_qualifier type_specifier_no_prec { $$ = $2; $$.precision = $1; + + if (!SupportsPrecision($2.type)) { + context->error(@1, "illegal type for precision qualifier", getBasicString($2.type)); + context->recover(); + } } ; @@ -1430,6 +1276,34 @@ precision_qualifier } ; +layout_qualifier + : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN { + ES3_ONLY("layout", @1, "qualifier"); + $$ = $3; + } + ; + +layout_qualifier_id_list + : layout_qualifier_id { + $$ = $1; + } + | layout_qualifier_id_list COMMA layout_qualifier_id { + $$ = context->joinLayoutQualifiers($1, $3); + } + ; + +layout_qualifier_id + : IDENTIFIER { + $$ = context->parseLayoutQualifier(*$1.string, @1); + } + | IDENTIFIER EQUAL INTCONSTANT { + $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); + } + | IDENTIFIER EQUAL UINTCONSTANT { + $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); + } + ; + type_specifier_no_prec : type_specifier_nonarray { $$ = $1; @@ -1461,6 +1335,10 @@ type_specifier_nonarray TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; $$.setBasic(EbtInt, qual, @1); } + | UINT_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUInt, qual, @1); + } | BOOL_TYPE { TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; $$.setBasic(EbtBool, qual, @1); @@ -1510,29 +1388,126 @@ type_specifier_nonarray $$.setBasic(EbtInt, qual, @1); $$.setAggregate(4); } + | UVEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUInt, qual, @1); + $$.setAggregate(2); + } + | UVEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUInt, qual, @1); + $$.setAggregate(3); + } + | UVEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUInt, qual, @1); + $$.setAggregate(4); + } | MATRIX2 { TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; $$.setBasic(EbtFloat, qual, @1); - $$.setAggregate(2, true); + $$.setMatrix(2, 2); } | MATRIX3 { TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; $$.setBasic(EbtFloat, qual, @1); - $$.setAggregate(3, true); + $$.setMatrix(3, 3); } | MATRIX4 { TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; $$.setBasic(EbtFloat, qual, @1); - $$.setAggregate(4, true); + $$.setMatrix(4, 4); + } + | MATRIX2x3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(2, 3); + } + | MATRIX3x2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(3, 2); + } + | MATRIX2x4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(2, 4); + } + | MATRIX4x2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(4, 2); + } + | MATRIX3x4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(3, 4); + } + | MATRIX4x3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(4, 3); } | SAMPLER2D { TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; $$.setBasic(EbtSampler2D, qual, @1); } + | SAMPLER3D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler3D, qual, @1); + } | SAMPLERCUBE { TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; $$.setBasic(EbtSamplerCube, qual, @1); } + | SAMPLER2DARRAY { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2DArray, qual, @1); + } + | ISAMPLER2D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtISampler2D, qual, @1); + } + | ISAMPLER3D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtISampler3D, qual, @1); + } + | ISAMPLERCUBE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtISamplerCube, qual, @1); + } + | ISAMPLER2DARRAY { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtISampler2DArray, qual, @1); + } + | USAMPLER2D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUSampler2D, qual, @1); + } + | USAMPLER3D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUSampler3D, qual, @1); + } + | USAMPLERCUBE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUSamplerCube, qual, @1); + } + | USAMPLER2DARRAY { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUSampler2DArray, qual, @1); + } + | SAMPLER2DSHADOW { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2DShadow, qual, @1); + } + | SAMPLERCUBESHADOW { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerCubeShadow, qual, @1); + } + | SAMPLER2DARRAYSHADOW { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2DArrayShadow, qual, @1); + } | SAMPLER_EXTERNAL_OES { if (!context->supportsExtension("GL_OES_EGL_image_external")) { context->error(@1, "unsupported type", "samplerExternalOES"); @@ -1567,24 +1542,10 @@ type_specifier_nonarray struct_specifier : STRUCT identifier LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { - if (context->reservedErrorCheck(@2, *$2.string)) - context->recover(); - - TType* structure = new TType(new TStructure($2.string, $5)); - TVariable* userTypeDef = new TVariable($2.string, *structure, true); - if (! context->symbolTable.insert(*userTypeDef)) { - context->error(@2, "redefinition", $2.string->c_str(), "struct"); - context->recover(); - } - $$.setBasic(EbtStruct, EvqTemporary, @1); - $$.userDef = structure; - context->exitStructDeclaration(); + $$ = context->addStructure(@1, @2, $2.string, $5); } | STRUCT LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { - TType* structure = new TType(new TStructure(NewPoolTString(""), $4)); - $$.setBasic(EbtStruct, EvqTemporary, @1); - $$.userDef = structure; - context->exitStructDeclaration(); + $$ = context->addStructure(@1, @$, NewPoolTString(""), $4); } ; @@ -1609,34 +1570,13 @@ struct_declaration_list struct_declaration : type_specifier struct_declarator_list SEMICOLON { - $$ = $2; - - if (context->voidErrorCheck(@1, (*$2)[0]->name(), $1)) { - context->recover(); - } - for (unsigned int i = 0; i < $$->size(); ++i) { - // - // Careful not to replace already known aspects of type, like array-ness - // - TType* type = (*$$)[i]->type(); - type->setBasicType($1.type); - type->setNominalSize($1.size); - type->setMatrix($1.matrix); - type->setPrecision($1.precision); - - // don't allow arrays of arrays - if (type->isArray()) { - if (context->arrayTypeErrorCheck(@1, $1)) - context->recover(); - } - if ($1.array) - type->setArraySize($1.arraySize); - if ($1.userDef) - type->setStruct($1.userDef->getStruct()); - - if (context->structNestingErrorCheck(@1, *(*$$)[i])) - context->recover(); - } + $$ = context->addStructDeclaratorList($1, $2); + } + | type_qualifier type_specifier struct_declarator_list SEMICOLON { + // ES3 Only, but errors should be handled elsewhere + $2.qualifier = $1.qualifier; + $2.layoutQualifier = $1.layoutQualifier; + $$ = context->addStructDeclaratorList($2, $3); } ; @@ -1656,19 +1596,19 @@ struct_declarator context->recover(); TType* type = new TType(EbtVoid, EbpUndefined); - $$ = new TField(type, $1.string); + $$ = new TField(type, $1.string, @1); } | identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { if (context->reservedErrorCheck(@1, *$1.string)) context->recover(); TType* type = new TType(EbtVoid, EbpUndefined); - int size = 0; + int size; if (context->arraySizeErrorCheck(@3, $3, size)) context->recover(); type->setArraySize(size); - $$ = new TField(type, $1.string); + $$ = new TField(type, $1.string, @1); } ; @@ -1902,7 +1842,7 @@ function_definition : function_prototype { TFunction* function = $1.function; - const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName()); + const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName(), context->shaderVersion); if (builtIn) { @@ -1910,7 +1850,7 @@ function_definition context->recover(); } - TFunction* prevDec = static_cast(context->symbolTable.find(function->getMangledName())); + TFunction* prevDec = static_cast(context->symbolTable.find(function->getMangledName(), context->shaderVersion)); // // Note: 'prevDec' could be 'function' if this is the first time we've seen function // as it would have just been put in the symbol table. Otherwise, we're looking up @@ -1961,7 +1901,7 @@ function_definition // // Insert the parameters with name in the symbol table. // - if (! context->symbolTable.insert(*variable)) { + if (! context->symbolTable.declare(variable)) { context->error(@1, "redefinition", variable->getName().c_str()); context->recover(); delete variable; @@ -1973,9 +1913,8 @@ function_definition paramNodes = context->intermediate.growAggregate( paramNodes, context->intermediate.addSymbol(variable->getUniqueId(), - variable->getName(), - variable->getType(), - @1), + variable->getName(), + variable->getType(), @1), @1); } else { paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, @1), @1); diff --git a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp index f2f918d77a..a6e7ab41a6 100644 --- a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp +++ b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp @@ -1,10 +1,14 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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/localintermediate.h" +#include "compiler/translator/SymbolTable.h" + +namespace +{ // // Two purposes: @@ -19,22 +23,40 @@ // Use this class to carry along data from node to node in // the traversal // -class TOutputTraverser : public TIntermTraverser { -public: - TOutputTraverser(TInfoSinkBase& i) : sink(i) { } +class TOutputTraverser : public TIntermTraverser +{ + public: + TOutputTraverser(TInfoSinkBase &i) + : sink(i) { } TInfoSinkBase& sink; -protected: - void visitSymbol(TIntermSymbol*); - void visitConstantUnion(TIntermConstantUnion*); - bool visitBinary(Visit visit, TIntermBinary*); - bool visitUnary(Visit visit, TIntermUnary*); - bool visitSelection(Visit visit, TIntermSelection*); - bool visitAggregate(Visit visit, TIntermAggregate*); - bool visitLoop(Visit visit, TIntermLoop*); - bool visitBranch(Visit visit, TIntermBranch*); + protected: + void visitSymbol(TIntermSymbol *); + void visitConstantUnion(TIntermConstantUnion *); + bool visitBinary(Visit visit, TIntermBinary *); + bool visitUnary(Visit visit, TIntermUnary *); + bool visitSelection(Visit visit, TIntermSelection *); + bool visitAggregate(Visit visit, TIntermAggregate *); + bool visitLoop(Visit visit, TIntermLoop *); + bool visitBranch(Visit visit, TIntermBranch *); }; +// +// Helper functions for printing, not part of traversing. +// +void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth) +{ + int i; + + sink.location(node->getLine()); + + for (i = 0; i < depth; ++i) + sink << " "; +} + +} // namespace anonymous + + TString TType::getCompleteString() const { TStringStream stream; @@ -43,29 +65,15 @@ TString TType::getCompleteString() const stream << getQualifierString() << " " << getPrecisionString() << " "; if (array) stream << "array[" << getArraySize() << "] of "; - if (matrix) - stream << static_cast(size) << "X" << static_cast(size) << " matrix of "; - else if (size > 1) - stream << static_cast(size) << "-component vector of "; + if (isMatrix()) + stream << getCols() << "X" << getRows() << " matrix of "; + else if (isVector()) + stream << getNominalSize() << "-component vector of "; stream << getBasicString(); return stream.str(); } -// -// Helper functions for printing, not part of traversing. -// - -void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth) -{ - int i; - - sink.location(node->getLine()); - - for (i = 0; i < depth; ++i) - sink << " "; -} - // // The rest of the file are the traversal functions. The last one // is the one that starts the traversal. @@ -75,57 +83,126 @@ void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth) // return false. // -void TOutputTraverser::visitSymbol(TIntermSymbol* node) +void TOutputTraverser::visitSymbol(TIntermSymbol *node) { - OutputTreeText(sink, node, depth); + OutputTreeText(sink, node, mDepth); sink << "'" << node->getSymbol() << "' "; sink << "(" << node->getCompleteString() << ")\n"; } -bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node) +bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) { TInfoSinkBase& out = sink; - OutputTreeText(out, node, depth); - - switch (node->getOp()) { - case EOpAssign: out << "move second child to first child"; break; - case EOpInitialize: out << "initialize first child with second child"; break; - case EOpAddAssign: out << "add second child into first child"; break; - case EOpSubAssign: out << "subtract second child into first child"; break; - case EOpMulAssign: out << "multiply second child into first child"; break; - case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break; - case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break; - case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break; - case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break; - case EOpDivAssign: out << "divide second child into first child"; break; - case EOpIndexDirect: out << "direct index"; break; - case EOpIndexIndirect: out << "indirect index"; break; - case EOpIndexDirectStruct: out << "direct index for structure"; break; - case EOpVectorSwizzle: out << "vector swizzle"; break; - - case EOpAdd: out << "add"; break; - case EOpSub: out << "subtract"; break; - case EOpMul: out << "component-wise multiply"; break; - case EOpDiv: out << "divide"; break; - case EOpEqual: out << "Compare Equal"; break; - case EOpNotEqual: out << "Compare Not Equal"; break; - case EOpLessThan: out << "Compare Less Than"; break; - case EOpGreaterThan: out << "Compare Greater Than"; break; - case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; - case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; - - case EOpVectorTimesScalar: out << "vector-scale"; break; - case EOpVectorTimesMatrix: out << "vector-times-matrix"; break; - case EOpMatrixTimesVector: out << "matrix-times-vector"; break; - case EOpMatrixTimesScalar: out << "matrix-scale"; break; - case EOpMatrixTimesMatrix: out << "matrix-multiply"; break; - - case EOpLogicalOr: out << "logical-or"; break; - case EOpLogicalXor: out << "logical-xor"; break; - case EOpLogicalAnd: out << "logical-and"; break; - default: out << ""; + OutputTreeText(out, node, mDepth); + + switch (node->getOp()) + { + case EOpAssign: + out << "move second child to first child"; + break; + case EOpInitialize: + out << "initialize first child with second child"; + break; + case EOpAddAssign: + out << "add second child into first child"; + break; + case EOpSubAssign: + out << "subtract second child into first child"; + break; + case EOpMulAssign: + out << "multiply second child into first child"; + break; + case EOpVectorTimesMatrixAssign: + out << "matrix mult second child into first child"; + break; + case EOpVectorTimesScalarAssign: + out << "vector scale second child into first child"; + break; + case EOpMatrixTimesScalarAssign: + out << "matrix scale second child into first child"; + break; + case EOpMatrixTimesMatrixAssign: + out << "matrix mult second child into first child"; + break; + case EOpDivAssign: + out << "divide second child into first child"; + break; + case EOpIndexDirect: + out << "direct index"; + break; + case EOpIndexIndirect: + out << "indirect index"; + break; + case EOpIndexDirectStruct: + out << "direct index for structure"; + break; + case EOpIndexDirectInterfaceBlock: + out << "direct index for interface block"; + break; + case EOpVectorSwizzle: + out << "vector swizzle"; + break; + + case EOpAdd: + out << "add"; + break; + case EOpSub: + out << "subtract"; + break; + case EOpMul: + out << "component-wise multiply"; + break; + case EOpDiv: + out << "divide"; + break; + case EOpEqual: + out << "Compare Equal"; + break; + case EOpNotEqual: + out << "Compare Not Equal"; + break; + case EOpLessThan: + out << "Compare Less Than"; + break; + case EOpGreaterThan: + out << "Compare Greater Than"; + break; + case EOpLessThanEqual: + out << "Compare Less Than or Equal"; + break; + case EOpGreaterThanEqual: + out << "Compare Greater Than or Equal"; + break; + + case EOpVectorTimesScalar: + out << "vector-scale"; + break; + case EOpVectorTimesMatrix: + out << "vector-times-matrix"; + break; + case EOpMatrixTimesVector: + out << "matrix-times-vector"; + break; + case EOpMatrixTimesScalar: + out << "matrix-scale"; + break; + case EOpMatrixTimesMatrix: + out << "matrix-multiply"; + break; + + case EOpLogicalOr: + out << "logical-or"; + break; + case EOpLogicalXor: + out << "logical-xor"; + break; + case EOpLogicalAnd: + out << "logical-and"; + break; + default: + out << ""; } out << " (" << node->getCompleteString() << ")"; @@ -135,63 +212,57 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node) return true; } -bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node) +bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) { TInfoSinkBase& out = sink; - OutputTreeText(out, node, depth); - - switch (node->getOp()) { - case EOpNegative: out << "Negate value"; break; - case EOpVectorLogicalNot: - case EOpLogicalNot: out << "Negate conditional"; break; - - case EOpPostIncrement: out << "Post-Increment"; break; - case EOpPostDecrement: out << "Post-Decrement"; break; - case EOpPreIncrement: out << "Pre-Increment"; break; - case EOpPreDecrement: out << "Pre-Decrement"; break; - - case EOpConvIntToBool: out << "Convert int to bool"; break; - case EOpConvFloatToBool:out << "Convert float to bool";break; - case EOpConvBoolToFloat:out << "Convert bool to float";break; - case EOpConvIntToFloat: out << "Convert int to float"; break; - case EOpConvFloatToInt: out << "Convert float to int"; break; - case EOpConvBoolToInt: out << "Convert bool to int"; break; - - case EOpRadians: out << "radians"; break; - case EOpDegrees: out << "degrees"; break; - case EOpSin: out << "sine"; break; - case EOpCos: out << "cosine"; break; - case EOpTan: out << "tangent"; break; - case EOpAsin: out << "arc sine"; break; - case EOpAcos: out << "arc cosine"; break; - case EOpAtan: out << "arc tangent"; break; - - case EOpExp: out << "exp"; break; - case EOpLog: out << "log"; break; - case EOpExp2: out << "exp2"; break; - case EOpLog2: out << "log2"; break; - case EOpSqrt: out << "sqrt"; break; - case EOpInverseSqrt: out << "inverse sqrt"; break; - - case EOpAbs: out << "Absolute value"; break; - case EOpSign: out << "Sign"; break; - case EOpFloor: out << "Floor"; break; - case EOpCeil: out << "Ceiling"; break; - case EOpFract: out << "Fraction"; break; - - case EOpLength: out << "length"; break; - case EOpNormalize: out << "normalize"; break; - // case EOpDPdx: out << "dPdx"; break; - // case EOpDPdy: out << "dPdy"; break; - // case EOpFwidth: out << "fwidth"; break; - - case EOpAny: out << "any"; break; - case EOpAll: out << "all"; break; - - default: - out.prefix(EPrefixError); - out << "Bad unary op"; + OutputTreeText(out, node, mDepth); + + switch (node->getOp()) + { + case EOpNegative: out << "Negate value"; break; + case EOpVectorLogicalNot: + case EOpLogicalNot: out << "Negate conditional"; break; + + case EOpPostIncrement: out << "Post-Increment"; break; + case EOpPostDecrement: out << "Post-Decrement"; break; + case EOpPreIncrement: out << "Pre-Increment"; break; + case EOpPreDecrement: out << "Pre-Decrement"; break; + + case EOpRadians: out << "radians"; break; + case EOpDegrees: out << "degrees"; break; + case EOpSin: out << "sine"; break; + case EOpCos: out << "cosine"; break; + case EOpTan: out << "tangent"; break; + case EOpAsin: out << "arc sine"; break; + case EOpAcos: out << "arc cosine"; break; + case EOpAtan: out << "arc tangent"; break; + + case EOpExp: out << "exp"; break; + case EOpLog: out << "log"; break; + case EOpExp2: out << "exp2"; break; + case EOpLog2: out << "log2"; break; + case EOpSqrt: out << "sqrt"; break; + case EOpInverseSqrt: out << "inverse sqrt"; break; + + case EOpAbs: out << "Absolute value"; break; + case EOpSign: out << "Sign"; break; + case EOpFloor: out << "Floor"; break; + case EOpCeil: out << "Ceiling"; break; + case EOpFract: out << "Fraction"; break; + + case EOpLength: out << "length"; break; + case EOpNormalize: out << "normalize"; break; + // case EOpDPdx: out << "dPdx"; break; + // case EOpDPdy: out << "dPdy"; break; + // case EOpFwidth: out << "fwidth"; break; + + case EOpAny: out << "any"; break; + case EOpAll: out << "all"; break; + + default: + out.prefix(EPrefixError); + out << "Bad unary op"; } out << " (" << node->getCompleteString() << ")"; @@ -201,74 +272,80 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node) return true; } -bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) { - TInfoSinkBase& out = sink; + TInfoSinkBase &out = sink; - if (node->getOp() == EOpNull) { + if (node->getOp() == EOpNull) + { out.prefix(EPrefixError); out << "node is still EOpNull!"; return true; } - OutputTreeText(out, node, depth); - - switch (node->getOp()) { - case EOpSequence: out << "Sequence\n"; return true; - case EOpComma: out << "Comma\n"; return true; - case EOpFunction: out << "Function Definition: " << node->getName(); break; - case EOpFunctionCall: out << "Function Call: " << node->getName(); break; - case EOpParameters: out << "Function Parameters: "; break; - - case EOpConstructFloat: out << "Construct float"; break; - case EOpConstructVec2: out << "Construct vec2"; break; - case EOpConstructVec3: out << "Construct vec3"; break; - case EOpConstructVec4: out << "Construct vec4"; break; - case EOpConstructBool: out << "Construct bool"; break; - case EOpConstructBVec2: out << "Construct bvec2"; break; - case EOpConstructBVec3: out << "Construct bvec3"; break; - case EOpConstructBVec4: out << "Construct bvec4"; break; - case EOpConstructInt: out << "Construct int"; break; - case EOpConstructIVec2: out << "Construct ivec2"; break; - case EOpConstructIVec3: out << "Construct ivec3"; break; - case EOpConstructIVec4: out << "Construct ivec4"; break; - case EOpConstructMat2: out << "Construct mat2"; break; - case EOpConstructMat3: out << "Construct mat3"; break; - case EOpConstructMat4: out << "Construct mat4"; break; - case EOpConstructStruct: out << "Construct structure"; break; - - case EOpLessThan: out << "Compare Less Than"; break; - case EOpGreaterThan: out << "Compare Greater Than"; break; - case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; - case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; - case EOpVectorEqual: out << "Equal"; break; - case EOpVectorNotEqual: out << "NotEqual"; break; - - case EOpMod: out << "mod"; break; - case EOpPow: out << "pow"; break; - - case EOpAtan: out << "arc tangent"; break; - - case EOpMin: out << "min"; break; - case EOpMax: out << "max"; break; - case EOpClamp: out << "clamp"; break; - case EOpMix: out << "mix"; break; - case EOpStep: out << "step"; break; - case EOpSmoothStep: out << "smoothstep"; break; - - case EOpDistance: out << "distance"; break; - case EOpDot: out << "dot-product"; break; - case EOpCross: out << "cross-product"; break; - case EOpFaceForward: out << "face-forward"; break; - case EOpReflect: out << "reflect"; break; - case EOpRefract: out << "refract"; break; - case EOpMul: out << "component-wise multiply"; break; - - case EOpDeclaration: out << "Declaration: "; break; - - default: - out.prefix(EPrefixError); - out << "Bad aggregation op"; + OutputTreeText(out, node, mDepth); + + switch (node->getOp()) + { + case EOpSequence: out << "Sequence\n"; return true; + case EOpComma: out << "Comma\n"; return true; + case EOpFunction: out << "Function Definition: " << node->getName(); break; + case EOpFunctionCall: out << "Function Call: " << node->getName(); break; + case EOpParameters: out << "Function Parameters: "; break; + + case EOpConstructFloat: out << "Construct float"; break; + case EOpConstructVec2: out << "Construct vec2"; break; + case EOpConstructVec3: out << "Construct vec3"; break; + case EOpConstructVec4: out << "Construct vec4"; break; + case EOpConstructBool: out << "Construct bool"; break; + case EOpConstructBVec2: out << "Construct bvec2"; break; + case EOpConstructBVec3: out << "Construct bvec3"; break; + case EOpConstructBVec4: out << "Construct bvec4"; break; + case EOpConstructInt: out << "Construct int"; break; + case EOpConstructIVec2: out << "Construct ivec2"; break; + case EOpConstructIVec3: out << "Construct ivec3"; break; + case EOpConstructIVec4: out << "Construct ivec4"; break; + case EOpConstructUInt: out << "Construct uint"; break; + case EOpConstructUVec2: out << "Construct uvec2"; break; + case EOpConstructUVec3: out << "Construct uvec3"; break; + case EOpConstructUVec4: out << "Construct uvec4"; break; + case EOpConstructMat2: out << "Construct mat2"; break; + case EOpConstructMat3: out << "Construct mat3"; break; + case EOpConstructMat4: out << "Construct mat4"; break; + case EOpConstructStruct: out << "Construct structure"; break; + + case EOpLessThan: out << "Compare Less Than"; break; + case EOpGreaterThan: out << "Compare Greater Than"; break; + case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; + case EOpVectorEqual: out << "Equal"; break; + case EOpVectorNotEqual: out << "NotEqual"; break; + + case EOpMod: out << "mod"; break; + case EOpPow: out << "pow"; break; + + case EOpAtan: out << "arc tangent"; break; + + case EOpMin: out << "min"; break; + case EOpMax: out << "max"; break; + case EOpClamp: out << "clamp"; break; + case EOpMix: out << "mix"; break; + case EOpStep: out << "step"; break; + case EOpSmoothStep: out << "smoothstep"; break; + + case EOpDistance: out << "distance"; break; + case EOpDot: out << "dot-product"; break; + case EOpCross: out << "cross-product"; break; + case EOpFaceForward: out << "face-forward"; break; + case EOpReflect: out << "reflect"; break; + case EOpRefract: out << "refract"; break; + case EOpMul: out << "component-wise multiply"; break; + + case EOpDeclaration: out << "Declaration: "; break; + + default: + out.prefix(EPrefixError); + out << "Bad aggregation op"; } if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) @@ -279,131 +356,156 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node) return true; } -bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node) +bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection *node) { - TInfoSinkBase& out = sink; + TInfoSinkBase &out = sink; - OutputTreeText(out, node, depth); + OutputTreeText(out, node, mDepth); out << "Test condition and select"; out << " (" << node->getCompleteString() << ")\n"; - ++depth; + ++mDepth; - OutputTreeText(sink, node, depth); + OutputTreeText(sink, node, mDepth); out << "Condition\n"; node->getCondition()->traverse(this); - OutputTreeText(sink, node, depth); - if (node->getTrueBlock()) { + OutputTreeText(sink, node, mDepth); + if (node->getTrueBlock()) + { out << "true case\n"; node->getTrueBlock()->traverse(this); - } else + } + else + { out << "true case is null\n"; + } - if (node->getFalseBlock()) { - OutputTreeText(sink, node, depth); + if (node->getFalseBlock()) + { + OutputTreeText(sink, node, mDepth); out << "false case\n"; node->getFalseBlock()->traverse(this); } - --depth; + --mDepth; return false; } -void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node) +void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node) { - TInfoSinkBase& out = sink; + TInfoSinkBase &out = sink; size_t size = node->getType().getObjectSize(); - for (size_t i = 0; i < size; i++) { - OutputTreeText(out, node, depth); - switch (node->getUnionArrayPointer()[i].getType()) { - case EbtBool: - if (node->getUnionArrayPointer()[i].getBConst()) - out << "true"; - else - out << "false"; - - out << " (" << "const bool" << ")"; - out << "\n"; - break; - case EbtFloat: - out << node->getUnionArrayPointer()[i].getFConst(); - out << " (const float)\n"; - break; - case EbtInt: - out << node->getUnionArrayPointer()[i].getIConst(); - out << " (const int)\n"; - break; - default: - out.message(EPrefixInternalError, node->getLine(), "Unknown constant"); - break; + for (size_t i = 0; i < size; i++) + { + OutputTreeText(out, node, mDepth); + switch (node->getUnionArrayPointer()[i].getType()) + { + case EbtBool: + if (node->getUnionArrayPointer()[i].getBConst()) + out << "true"; + else + out << "false"; + + out << " (" << "const bool" << ")"; + out << "\n"; + break; + case EbtFloat: + out << node->getUnionArrayPointer()[i].getFConst(); + out << " (const float)\n"; + break; + case EbtInt: + out << node->getUnionArrayPointer()[i].getIConst(); + out << " (const int)\n"; + break; + case EbtUInt: + out << node->getUnionArrayPointer()[i].getUConst(); + out << " (const uint)\n"; + break; + default: + out.message(EPrefixInternalError, node->getLine(), "Unknown constant"); + break; } } } -bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node) +bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node) { - TInfoSinkBase& out = sink; + TInfoSinkBase &out = sink; - OutputTreeText(out, node, depth); + OutputTreeText(out, node, mDepth); out << "Loop with condition "; if (node->getType() == ELoopDoWhile) out << "not "; out << "tested first\n"; - ++depth; + ++mDepth; - OutputTreeText(sink, node, depth); - if (node->getCondition()) { + OutputTreeText(sink, node, mDepth); + if (node->getCondition()) + { out << "Loop Condition\n"; node->getCondition()->traverse(this); - } else + } + else + { out << "No loop condition\n"; + } - OutputTreeText(sink, node, depth); - if (node->getBody()) { + OutputTreeText(sink, node, mDepth); + if (node->getBody()) + { out << "Loop Body\n"; node->getBody()->traverse(this); - } else + } + else + { out << "No loop body\n"; + } - if (node->getExpression()) { - OutputTreeText(sink, node, depth); + if (node->getExpression()) + { + OutputTreeText(sink, node, mDepth); out << "Loop Terminal Expression\n"; node->getExpression()->traverse(this); } - --depth; + --mDepth; return false; } -bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node) +bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node) { - TInfoSinkBase& out = sink; + TInfoSinkBase &out = sink; - OutputTreeText(out, node, depth); + OutputTreeText(out, node, mDepth); - switch (node->getFlowOp()) { - case EOpKill: out << "Branch: Kill"; break; - case EOpBreak: out << "Branch: Break"; break; - case EOpContinue: out << "Branch: Continue"; break; - case EOpReturn: out << "Branch: Return"; break; - default: out << "Branch: Unknown Branch"; break; + switch (node->getFlowOp()) + { + case EOpKill: out << "Branch: Kill"; break; + case EOpBreak: out << "Branch: Break"; break; + case EOpContinue: out << "Branch: Continue"; break; + case EOpReturn: out << "Branch: Return"; break; + default: out << "Branch: Unknown Branch"; break; } - if (node->getExpression()) { + if (node->getExpression()) + { out << " with expression\n"; - ++depth; + ++mDepth; node->getExpression()->traverse(this); - --depth; - } else + --mDepth; + } + else + { out << "\n"; + } return false; } @@ -413,12 +515,12 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node) // Individual functions can be initialized to 0 to skip processing of that // type of node. It's children will still be processed. // -void TIntermediate::outputTree(TIntermNode* root) +void TIntermediate::outputTree(TIntermNode *root) { - if (root == 0) + if (root == NULL) return; - TOutputTraverser it(infoSink.info); + TOutputTraverser it(mInfoSink.info); root->traverse(&it); } diff --git a/src/3rdparty/angle/src/compiler/translator/intermediate.h b/src/3rdparty/angle/src/compiler/translator/intermediate.h index 8f9fe23d3b..892f2849e0 100644 --- a/src/3rdparty/angle/src/compiler/translator/intermediate.h +++ b/src/3rdparty/angle/src/compiler/translator/intermediate.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -8,17 +8,19 @@ // Definition of the in-memory high-level intermediate representation // of shaders. This is a tree that parser creates. // -// Nodes in the tree are defined as a hierarchy of classes derived from +// Nodes in the tree are defined as a hierarchy of classes derived from // TIntermNode. Each is a node in a tree. There is no preset branching factor; // each node can have it's own type of list of children. // -#ifndef __INTERMEDIATE_H -#define __INTERMEDIATE_H +#ifndef COMPILER_TRANSLATOR_INTERMEDIATE_H_ +#define COMPILER_TRANSLATOR_INTERMEDIATE_H_ #include "GLSLANG/ShaderLang.h" #include +#include + #include "compiler/translator/Common.h" #include "compiler/translator/Types.h" #include "compiler/translator/ConstantUnion.h" @@ -26,10 +28,11 @@ // // Operators used by the high-level (parse tree) representation. // -enum TOperator { +enum TOperator +{ EOpNull, // if in a node, should only mean a node is still being built EOpSequence, // denotes a list of statements, or parameters, etc. - EOpFunctionCall, + EOpFunctionCall, EOpFunction, // For function definition EOpParameters, // an aggregate listing the parameters to a function @@ -49,13 +52,6 @@ enum TOperator { EOpPreIncrement, EOpPreDecrement, - EOpConvIntToBool, - EOpConvFloatToBool, - EOpConvBoolToFloat, - EOpConvIntToFloat, - EOpConvFloatToInt, - EOpConvBoolToInt, - // // binary operations // @@ -86,6 +82,7 @@ enum TOperator { EOpIndexDirect, EOpIndexIndirect, EOpIndexDirectStruct, + EOpIndexDirectInterfaceBlock, EOpVectorSwizzle, @@ -155,6 +152,7 @@ enum TOperator { // EOpConstructInt, + EOpConstructUInt, EOpConstructBool, EOpConstructFloat, EOpConstructVec2, @@ -166,6 +164,9 @@ enum TOperator { EOpConstructIVec2, EOpConstructIVec3, EOpConstructIVec4, + EOpConstructUVec2, + EOpConstructUVec3, + EOpConstructUVec4, EOpConstructMat2, EOpConstructMat3, EOpConstructMat4, @@ -187,8 +188,6 @@ enum TOperator { EOpDivAssign }; -extern const char* getOperatorString(TOperator op); - class TIntermTraverser; class TIntermAggregate; class TIntermBinary; @@ -199,347 +198,454 @@ class TIntermTyped; class TIntermSymbol; class TIntermLoop; class TInfoSink; +class TIntermRaw; // // Base class for the tree nodes // -class TIntermNode { -public: +class TIntermNode +{ + public: POOL_ALLOCATOR_NEW_DELETE(); - TIntermNode() { + TIntermNode() + { // TODO: Move this to TSourceLoc constructor // after getting rid of TPublicType. - line.first_file = line.last_file = 0; - line.first_line = line.last_line = 0; + mLine.first_file = mLine.last_file = 0; + mLine.first_line = mLine.last_line = 0; } virtual ~TIntermNode() { } - const TSourceLoc& getLine() const { return line; } - void setLine(const TSourceLoc& l) { line = l; } + const TSourceLoc &getLine() const { return mLine; } + void setLine(const TSourceLoc &l) { mLine = l; } - virtual void traverse(TIntermTraverser*) = 0; - virtual TIntermTyped* getAsTyped() { return 0; } - virtual TIntermConstantUnion* getAsConstantUnion() { return 0; } - virtual TIntermAggregate* getAsAggregate() { return 0; } - virtual TIntermBinary* getAsBinaryNode() { return 0; } - virtual TIntermUnary* getAsUnaryNode() { return 0; } - virtual TIntermSelection* getAsSelectionNode() { return 0; } - virtual TIntermSymbol* getAsSymbolNode() { return 0; } - virtual TIntermLoop* getAsLoopNode() { return 0; } + virtual void traverse(TIntermTraverser *) = 0; + virtual TIntermTyped *getAsTyped() { return 0; } + virtual TIntermConstantUnion *getAsConstantUnion() { return 0; } + virtual TIntermAggregate *getAsAggregate() { return 0; } + virtual TIntermBinary *getAsBinaryNode() { return 0; } + virtual TIntermUnary *getAsUnaryNode() { return 0; } + virtual TIntermSelection *getAsSelectionNode() { return 0; } + virtual TIntermSymbol *getAsSymbolNode() { return 0; } + virtual TIntermLoop *getAsLoopNode() { return 0; } + virtual TIntermRaw *getAsRawNode() { return 0; } // Replace a child node. Return true if |original| is a child // node and it is replaced; otherwise, return false. virtual bool replaceChildNode( TIntermNode *original, TIntermNode *replacement) = 0; -protected: - TSourceLoc line; + // For traversing a tree in no particular order, but using + // heap memory. + virtual void enqueueChildren(std::queue *nodeQueue) const = 0; + + protected: + TSourceLoc mLine; }; // // This is just to help yacc. // -struct TIntermNodePair { - TIntermNode* node1; - TIntermNode* node2; +struct TIntermNodePair +{ + TIntermNode *node1; + TIntermNode *node2; }; // // Intermediate class for nodes that have a type. // -class TIntermTyped : public TIntermNode { -public: - TIntermTyped(const TType& t) : type(t) { } - virtual TIntermTyped* getAsTyped() { return this; } +class TIntermTyped : public TIntermNode +{ + public: + TIntermTyped(const TType &t) : mType(t) { } + virtual TIntermTyped *getAsTyped() { return this; } virtual bool hasSideEffects() const = 0; - void setType(const TType& t) { type = t; } - const TType& getType() const { return type; } - TType* getTypePointer() { return &type; } - - TBasicType getBasicType() const { return type.getBasicType(); } - TQualifier getQualifier() const { return type.getQualifier(); } - TPrecision getPrecision() const { return type.getPrecision(); } - int getNominalSize() const { return type.getNominalSize(); } - - bool isMatrix() const { return type.isMatrix(); } - bool isArray() const { return type.isArray(); } - bool isVector() const { return type.isVector(); } - bool isScalar() const { return type.isScalar(); } - const char* getBasicString() const { return type.getBasicString(); } - const char* getQualifierString() const { return type.getQualifierString(); } - TString getCompleteString() const { return type.getCompleteString(); } - - int totalRegisterCount() const { return type.totalRegisterCount(); } - int elementRegisterCount() const { return type.elementRegisterCount(); } - int getArraySize() const { return type.getArraySize(); } - -protected: - TType type; + void setType(const TType &t) { mType = t; } + const TType &getType() const { return mType; } + TType *getTypePointer() { return &mType; } + + TBasicType getBasicType() const { return mType.getBasicType(); } + TQualifier getQualifier() const { return mType.getQualifier(); } + TPrecision getPrecision() const { return mType.getPrecision(); } + int getCols() const { return mType.getCols(); } + int getRows() const { return mType.getRows(); } + int getNominalSize() const { return mType.getNominalSize(); } + int getSecondarySize() const { return mType.getSecondarySize(); } + + bool isInterfaceBlock() const { return mType.isInterfaceBlock(); } + bool isMatrix() const { return mType.isMatrix(); } + bool isArray() const { return mType.isArray(); } + bool isVector() const { return mType.isVector(); } + bool isScalar() const { return mType.isScalar(); } + bool isScalarInt() const { return mType.isScalarInt(); } + const char *getBasicString() const { return mType.getBasicString(); } + const char *getQualifierString() const { return mType.getQualifierString(); } + TString getCompleteString() const { return mType.getCompleteString(); } + + int getArraySize() const { return mType.getArraySize(); } + + protected: + TType mType; }; // // Handle for, do-while, and while loops. // -enum TLoopType { +enum TLoopType +{ ELoopFor, ELoopWhile, ELoopDoWhile }; -class TIntermLoop : public TIntermNode { -public: - TIntermLoop(TLoopType aType, - TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr, - TIntermNode* aBody) : - type(aType), - init(aInit), - cond(aCond), - expr(aExpr), - body(aBody), - unrollFlag(false) { } - - virtual TIntermLoop* getAsLoopNode() { return this; } - virtual void traverse(TIntermTraverser*); +class TIntermLoop : public TIntermNode +{ + public: + TIntermLoop(TLoopType type, + TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr, + TIntermNode *body) + : mType(type), + mInit(init), + mCond(cond), + mExpr(expr), + mBody(body), + mUnrollFlag(false) { } + + virtual TIntermLoop *getAsLoopNode() { return this; } + virtual void traverse(TIntermTraverser *); virtual bool replaceChildNode( TIntermNode *original, TIntermNode *replacement); - TLoopType getType() const { return type; } - TIntermNode* getInit() { return init; } - TIntermTyped* getCondition() { return cond; } - TIntermTyped* getExpression() { return expr; } - TIntermNode* getBody() { return body; } + TLoopType getType() const { return mType; } + TIntermNode *getInit() { return mInit; } + TIntermTyped *getCondition() { return mCond; } + TIntermTyped *getExpression() { return mExpr; } + TIntermNode *getBody() { return mBody; } - void setUnrollFlag(bool flag) { unrollFlag = flag; } - bool getUnrollFlag() { return unrollFlag; } + void setUnrollFlag(bool flag) { mUnrollFlag = flag; } + bool getUnrollFlag() const { return mUnrollFlag; } -protected: - TLoopType type; - TIntermNode* init; // for-loop initialization - TIntermTyped* cond; // loop exit condition - TIntermTyped* expr; // for-loop expression - TIntermNode* body; // loop body + virtual void enqueueChildren(std::queue *nodeQueue) const; - bool unrollFlag; // Whether the loop should be unrolled or not. + protected: + TLoopType mType; + TIntermNode *mInit; // for-loop initialization + TIntermTyped *mCond; // loop exit condition + TIntermTyped *mExpr; // for-loop expression + TIntermNode *mBody; // loop body + + bool mUnrollFlag; // Whether the loop should be unrolled or not. }; // // Handle break, continue, return, and kill. // -class TIntermBranch : public TIntermNode { -public: - TIntermBranch(TOperator op, TIntermTyped* e) : - flowOp(op), - expression(e) { } +class TIntermBranch : public TIntermNode +{ + public: + TIntermBranch(TOperator op, TIntermTyped *e) + : mFlowOp(op), + mExpression(e) { } - virtual void traverse(TIntermTraverser*); + virtual void traverse(TIntermTraverser *); virtual bool replaceChildNode( TIntermNode *original, TIntermNode *replacement); - TOperator getFlowOp() { return flowOp; } - TIntermTyped* getExpression() { return expression; } + TOperator getFlowOp() { return mFlowOp; } + TIntermTyped* getExpression() { return mExpression; } + + virtual void enqueueChildren(std::queue *nodeQueue) const; protected: - TOperator flowOp; - TIntermTyped* expression; // non-zero except for "return exp;" statements + TOperator mFlowOp; + TIntermTyped *mExpression; // non-zero except for "return exp;" statements }; // // Nodes that correspond to symbols or constants in the source code. // -class TIntermSymbol : public TIntermTyped { -public: - // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from - // per process globalpoolallocator, then it causes increased memory usage per compile - // it is essential to use "symbol = sym" to assign to symbol - TIntermSymbol(int i, const TString& sym, const TType& t) : - TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; } +class TIntermSymbol : public TIntermTyped +{ + public: + // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. + // If sym comes from per process globalpoolallocator, then it causes increased memory usage + // per compile it is essential to use "symbol = sym" to assign to symbol + TIntermSymbol(int id, const TString &symbol, const TType &type) + : TIntermTyped(type), + mId(id) + { + mSymbol = symbol; + } virtual bool hasSideEffects() const { return false; } - int getId() const { return id; } - const TString& getSymbol() const { return symbol; } + int getId() const { return mId; } + const TString &getSymbol() const { return mSymbol; } + + void setId(int newId) { mId = newId; } + + virtual void traverse(TIntermTraverser *); + virtual TIntermSymbol *getAsSymbolNode() { return this; } + virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } + + virtual void enqueueChildren(std::queue *nodeQueue) const {} - void setId(int newId) { id = newId; } - void setSymbol(const TString& sym) { symbol = sym; } + protected: + int mId; + TString mSymbol; +}; - const TString& getOriginalSymbol() const { return originalSymbol; } +// A Raw node stores raw code, that the translator will insert verbatim +// into the output stream. Useful for transformation operations that make +// complex code that might not fit naturally into the GLSL model. +class TIntermRaw : public TIntermTyped +{ + public: + TIntermRaw(const TType &type, const TString &rawText) + : TIntermTyped(type), + mRawText(rawText) { } + + virtual bool hasSideEffects() const { return false; } - virtual void traverse(TIntermTraverser*); - virtual TIntermSymbol* getAsSymbolNode() { return this; } + TString getRawText() const { return mRawText; } + + virtual void traverse(TIntermTraverser *); + + virtual TIntermRaw *getAsRawNode() { return this; } virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } + virtual void enqueueChildren(std::queue *nodeQueue) const {} -protected: - int id; - TString symbol; - TString originalSymbol; + protected: + TString mRawText; }; -class TIntermConstantUnion : public TIntermTyped { -public: - TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } +class TIntermConstantUnion : public TIntermTyped +{ + public: + TIntermConstantUnion(ConstantUnion *unionPointer, const TType &type) + : TIntermTyped(type), + mUnionArrayPointer(unionPointer) { } virtual bool hasSideEffects() const { return false; } - ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; } - - int getIConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; } - float getFConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; } - bool getBConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; } + ConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; } - virtual TIntermConstantUnion* getAsConstantUnion() { return this; } - virtual void traverse(TIntermTraverser*); + int getIConst(size_t index) const + { + return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0; + } + unsigned int getUConst(size_t index) const + { + return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0; + } + float getFConst(size_t index) const + { + return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f; + } + bool getBConst(size_t index) const + { + return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false; + } + + virtual TIntermConstantUnion *getAsConstantUnion() { return this; } + virtual void traverse(TIntermTraverser *); virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } - TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); + TIntermTyped *fold(TOperator, TIntermTyped *, TInfoSink &); -protected: - ConstantUnion *unionArrayPointer; + virtual void enqueueChildren(std::queue *nodeQueue) const {} + + protected: + ConstantUnion *mUnionArrayPointer; }; // // Intermediate class for node types that hold operators. // -class TIntermOperator : public TIntermTyped { -public: - TOperator getOp() const { return op; } - void setOp(TOperator o) { op = o; } +class TIntermOperator : public TIntermTyped +{ + public: + TOperator getOp() const { return mOp; } + void setOp(TOperator op) { mOp = op; } bool isAssignment() const; bool isConstructor() const; virtual bool hasSideEffects() const { return isAssignment(); } -protected: - TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {} - TIntermOperator(TOperator o, const TType& t) : TIntermTyped(t), op(o) {} - TOperator op; + protected: + TIntermOperator(TOperator op) + : TIntermTyped(TType(EbtFloat, EbpUndefined)), + mOp(op) {} + TIntermOperator(TOperator op, const TType &type) + : TIntermTyped(type), + mOp(op) {} + + TOperator mOp; }; // // Nodes for all the basic binary math operators. // -class TIntermBinary : public TIntermOperator { -public: - TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {} +class TIntermBinary : public TIntermOperator +{ + public: + TIntermBinary(TOperator op) + : TIntermOperator(op), + mAddIndexClamp(false) {} - virtual TIntermBinary* getAsBinaryNode() { return this; } - virtual void traverse(TIntermTraverser*); + virtual TIntermBinary *getAsBinaryNode() { return this; } + virtual void traverse(TIntermTraverser *); virtual bool replaceChildNode( TIntermNode *original, TIntermNode *replacement); - virtual bool hasSideEffects() const { return (isAssignment() || left->hasSideEffects() || right->hasSideEffects()); } + virtual bool hasSideEffects() const + { + return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects(); + } - void setLeft(TIntermTyped* n) { left = n; } - void setRight(TIntermTyped* n) { right = n; } - TIntermTyped* getLeft() const { return left; } - TIntermTyped* getRight() const { return right; } - bool promote(TInfoSink&); + void setLeft(TIntermTyped *node) { mLeft = node; } + void setRight(TIntermTyped *node) { mRight = node; } + TIntermTyped *getLeft() const { return mLeft; } + TIntermTyped *getRight() const { return mRight; } + bool promote(TInfoSink &); - void setAddIndexClamp() { addIndexClamp = true; } - bool getAddIndexClamp() { return addIndexClamp; } + void setAddIndexClamp() { mAddIndexClamp = true; } + bool getAddIndexClamp() { return mAddIndexClamp; } -protected: - TIntermTyped* left; - TIntermTyped* right; + virtual void enqueueChildren(std::queue *nodeQueue) const; + + protected: + TIntermTyped* mLeft; + TIntermTyped* mRight; // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. - bool addIndexClamp; + bool mAddIndexClamp; }; // // Nodes for unary math operators. // -class TIntermUnary : public TIntermOperator { -public: - TIntermUnary(TOperator o, const TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {} - TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {} - - virtual void traverse(TIntermTraverser*); - virtual TIntermUnary* getAsUnaryNode() { return this; } +class TIntermUnary : public TIntermOperator +{ + public: + TIntermUnary(TOperator op, const TType &type) + : TIntermOperator(op, type), + mOperand(NULL), + mUseEmulatedFunction(false) {} + TIntermUnary(TOperator op) + : TIntermOperator(op), + mOperand(NULL), + mUseEmulatedFunction(false) {} + + virtual void traverse(TIntermTraverser *); + virtual TIntermUnary *getAsUnaryNode() { return this; } virtual bool replaceChildNode( TIntermNode *original, TIntermNode *replacement); - virtual bool hasSideEffects() const { return (isAssignment() || operand->hasSideEffects()); } + virtual bool hasSideEffects() const + { + return isAssignment() || mOperand->hasSideEffects(); + } - void setOperand(TIntermTyped* o) { operand = o; } - TIntermTyped* getOperand() { return operand; } - bool promote(TInfoSink&); + void setOperand(TIntermTyped *operand) { mOperand = operand; } + TIntermTyped *getOperand() { return mOperand; } + bool promote(TInfoSink &); - void setUseEmulatedFunction() { useEmulatedFunction = true; } - bool getUseEmulatedFunction() { return useEmulatedFunction; } + void setUseEmulatedFunction() { mUseEmulatedFunction = true; } + bool getUseEmulatedFunction() { return mUseEmulatedFunction; } -protected: - TIntermTyped* operand; + virtual void enqueueChildren(std::queue *nodeQueue) const; + + protected: + TIntermTyped *mOperand; // If set to true, replace the built-in function call with an emulated one // to work around driver bugs. - bool useEmulatedFunction; + bool mUseEmulatedFunction; }; -typedef TVector TIntermSequence; +typedef TVector TIntermSequence; typedef TVector TQualifierList; // // Nodes that operate on an arbitrary sized set of children. // -class TIntermAggregate : public TIntermOperator { -public: - TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { } - TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { } +class TIntermAggregate : public TIntermOperator +{ + public: + TIntermAggregate() + : TIntermOperator(EOpNull), + mUserDefined(false), + mUseEmulatedFunction(false) { } + TIntermAggregate(TOperator op) + : TIntermOperator(op), + mUseEmulatedFunction(false) { } ~TIntermAggregate() { } - virtual TIntermAggregate* getAsAggregate() { return this; } - virtual void traverse(TIntermTraverser*); + virtual TIntermAggregate *getAsAggregate() { return this; } + virtual void traverse(TIntermTraverser *); virtual bool replaceChildNode( TIntermNode *original, TIntermNode *replacement); // Conservatively assume function calls and other aggregate operators have side-effects virtual bool hasSideEffects() const { return true; } - TIntermSequence& getSequence() { return sequence; } + TIntermSequence *getSequence() { return &mSequence; } - void setName(const TString& n) { name = n; } - const TString& getName() const { return name; } + void setName(const TString &name) { mName = name; } + const TString &getName() const { return mName; } - void setUserDefined() { userDefined = true; } - bool isUserDefined() const { return userDefined; } + void setUserDefined() { mUserDefined = true; } + bool isUserDefined() const { return mUserDefined; } - void setOptimize(bool o) { optimize = o; } - bool getOptimize() { return optimize; } - void setDebug(bool d) { debug = d; } - bool getDebug() { return debug; } + void setOptimize(bool optimize) { mOptimize = optimize; } + bool getOptimize() const { return mOptimize; } + void setDebug(bool debug) { mDebug = debug; } + bool getDebug() const { return mDebug; } - void setUseEmulatedFunction() { useEmulatedFunction = true; } - bool getUseEmulatedFunction() { return useEmulatedFunction; } + void setUseEmulatedFunction() { mUseEmulatedFunction = true; } + bool getUseEmulatedFunction() { return mUseEmulatedFunction; } -protected: - TIntermAggregate(const TIntermAggregate&); // disallow copy constructor - TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator - TIntermSequence sequence; - TString name; - bool userDefined; // used for user defined function names + virtual void enqueueChildren(std::queue *nodeQueue) const; - bool optimize; - bool debug; + protected: + TIntermAggregate(const TIntermAggregate &); // disallow copy constructor + TIntermAggregate &operator=(const TIntermAggregate &); // disallow assignment operator + TIntermSequence mSequence; + TString mName; + bool mUserDefined; // used for user defined function names + + bool mOptimize; + bool mDebug; // If set to true, replace the built-in function call with an emulated one // to work around driver bugs. - bool useEmulatedFunction; + bool mUseEmulatedFunction; }; // // For if tests. Simplified since there is no switch statement. // -class TIntermSelection : public TIntermTyped { -public: - TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : - TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} - TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : - TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} - - virtual void traverse(TIntermTraverser*); +class TIntermSelection : public TIntermTyped +{ + public: + TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB) + : TIntermTyped(TType(EbtVoid, EbpUndefined)), + mCondition(cond), + mTrueBlock(trueB), + mFalseBlock(falseB) {} + TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB, + const TType &type) + : TIntermTyped(type), + mCondition(cond), + mTrueBlock(trueB), + mFalseBlock(falseB) {} + + virtual void traverse(TIntermTraverser *); virtual bool replaceChildNode( TIntermNode *original, TIntermNode *replacement); @@ -547,15 +653,17 @@ public: virtual bool hasSideEffects() const { return true; } bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } - TIntermNode* getCondition() const { return condition; } - TIntermNode* getTrueBlock() const { return trueBlock; } - TIntermNode* getFalseBlock() const { return falseBlock; } - TIntermSelection* getAsSelectionNode() { return this; } + TIntermNode *getCondition() const { return mCondition; } + TIntermNode *getTrueBlock() const { return mTrueBlock; } + TIntermNode *getFalseBlock() const { return mFalseBlock; } + TIntermSelection *getAsSelectionNode() { return this; } + + virtual void enqueueChildren(std::queue *nodeQueue) const; protected: - TIntermTyped* condition; - TIntermNode* trueBlock; - TIntermNode* falseBlock; + TIntermTyped *mCondition; + TIntermNode *mTrueBlock; + TIntermNode *mFalseBlock; }; enum Visit @@ -566,7 +674,7 @@ enum Visit }; // -// For traversing the tree. User should derive from this, +// For traversing the tree. User should derive from this, // put their traversal specific data in it, and then pass // it to a Traverse method. // @@ -575,44 +683,47 @@ enum Visit // class TIntermTraverser { -public: + public: POOL_ALLOCATOR_NEW_DELETE(); - TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : - preVisit(preVisit), - inVisit(inVisit), - postVisit(postVisit), - rightToLeft(rightToLeft), - depth(0), - maxDepth(0) {} + // TODO(zmo): remove default values. + TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, + bool rightToLeft = false) + : preVisit(preVisit), + inVisit(inVisit), + postVisit(postVisit), + rightToLeft(rightToLeft), + mDepth(0), + mMaxDepth(0) {} virtual ~TIntermTraverser() {} - virtual void visitSymbol(TIntermSymbol*) {} - virtual void visitConstantUnion(TIntermConstantUnion*) {} - virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;} - virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;} - virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;} - virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} - virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} - virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} + virtual void visitSymbol(TIntermSymbol *) {} + virtual void visitRaw(TIntermRaw *) {} + virtual void visitConstantUnion(TIntermConstantUnion *) {} + virtual bool visitBinary(Visit, TIntermBinary *) { return true; } + virtual bool visitUnary(Visit, TIntermUnary *) { return true; } + virtual bool visitSelection(Visit, TIntermSelection *) { return true; } + virtual bool visitAggregate(Visit, TIntermAggregate *) { return true; } + virtual bool visitLoop(Visit, TIntermLoop *) { return true; } + virtual bool visitBranch(Visit, TIntermBranch *) { return true; } - int getMaxDepth() const {return maxDepth;} + int getMaxDepth() const { return mMaxDepth; } void incrementDepth(TIntermNode *current) { - depth++; - maxDepth = std::max(maxDepth, depth); - path.push_back(current); + mDepth++; + mMaxDepth = std::max(mMaxDepth, mDepth); + mPath.push_back(current); } void decrementDepth() { - depth--; - path.pop_back(); + mDepth--; + mPath.pop_back(); } TIntermNode *getParentNode() { - return path.size() == 0 ? NULL : path.back(); + return mPath.size() == 0 ? NULL : mPath.back(); } // Return the original name if hash function pointer is NULL; @@ -624,12 +735,37 @@ public: const bool postVisit; const bool rightToLeft; -protected: - int depth; - int maxDepth; + protected: + int mDepth; + int mMaxDepth; // All the nodes from root to the current node's parent during traversing. - TVector path; + TVector mPath; +}; + +// +// For traversing the tree, and computing max depth. +// Takes a maximum depth limit to prevent stack overflow. +// +class TMaxDepthTraverser : public TIntermTraverser +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TMaxDepthTraverser(int depthLimit) + : TIntermTraverser(true, true, false, false), + mDepthLimit(depthLimit) { } + + virtual bool visitBinary(Visit, TIntermBinary *) { return depthCheck(); } + virtual bool visitUnary(Visit, TIntermUnary *) { return depthCheck(); } + virtual bool visitSelection(Visit, TIntermSelection *) { return depthCheck(); } + virtual bool visitAggregate(Visit, TIntermAggregate *) { return depthCheck(); } + virtual bool visitLoop(Visit, TIntermLoop *) { return depthCheck(); } + virtual bool visitBranch(Visit, TIntermBranch *) { return depthCheck(); } + +protected: + bool depthCheck() const { return mMaxDepth < mDepthLimit; } + + int mDepthLimit; }; -#endif // __INTERMEDIATE_H +#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/length_limits.h b/src/3rdparty/angle/src/compiler/translator/length_limits.h new file mode 100644 index 0000000000..df70ee5d84 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/length_limits.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 2011-2014 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. +// + +// +// length_limits.h +// + +#if !defined(__LENGTH_LIMITS_H) +#define __LENGTH_LIMITS_H 1 + +#include "GLSLANG/ShaderLang.h" + +// These constants are factored out from the rest of the headers to +// make it easier to reference them from the compiler sources. + +size_t GetGlobalMaxTokenSize(ShShaderSpec spec); + +#endif // !(defined(__LENGTH_LIMITS_H) diff --git a/src/3rdparty/angle/src/compiler/translator/localintermediate.h b/src/3rdparty/angle/src/compiler/translator/localintermediate.h index b582e02f5d..0809bbd362 100644 --- a/src/3rdparty/angle/src/compiler/translator/localintermediate.h +++ b/src/3rdparty/angle/src/compiler/translator/localintermediate.h @@ -1,17 +1,16 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // -#ifndef _LOCAL_INTERMEDIATE_INCLUDED_ -#define _LOCAL_INTERMEDIATE_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_LOCAL_INTERMEDIATE_H_ +#define COMPILER_TRANSLATOR_LOCAL_INTERMEDIATE_H_ -#include "GLSLANG/ShaderLang.h" #include "compiler/translator/intermediate.h" -#include "compiler/translator/SymbolTable.h" -struct TVectorFields { +struct TVectorFields +{ int offsets[4]; int num; }; @@ -20,38 +19,49 @@ struct TVectorFields { // Set of helper functions to help parse and build the tree. // class TInfoSink; -class TIntermediate { -public: +class TIntermediate +{ + public: POOL_ALLOCATOR_NEW_DELETE(); - TIntermediate(TInfoSink& i) : infoSink(i) { } - - TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TSourceLoc&); - TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*); - TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&, TSymbolTable&); - TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); - TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&); - TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, const TSourceLoc&, TSymbolTable&); - TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&); - TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&); - TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, const TSourceLoc&); - TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&); - TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&); - TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); - TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, const TSourceLoc&); - TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ; - bool parseConstTree(const TSourceLoc&, TIntermNode*, ConstantUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false); - TIntermNode* addLoop(TLoopType, TIntermNode*, TIntermTyped*, TIntermTyped*, TIntermNode*, const TSourceLoc&); - TIntermBranch* addBranch(TOperator, const TSourceLoc&); - TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&); - TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&); - bool postProcess(TIntermNode*); - void remove(TIntermNode*); - void outputTree(TIntermNode*); - -private: - void operator=(TIntermediate&); // prevent assignments - - TInfoSink& infoSink; + TIntermediate(TInfoSink &i) + : mInfoSink(i) { } + + TIntermSymbol *addSymbol( + int id, const TString &, const TType &, const TSourceLoc &); + TIntermTyped *addBinaryMath( + TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); + TIntermTyped *addAssign( + TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); + TIntermTyped *addIndex( + TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &); + TIntermTyped *addUnaryMath( + TOperator op, TIntermNode *child, const TSourceLoc &); + TIntermAggregate *growAggregate( + TIntermNode *left, TIntermNode *right, const TSourceLoc &); + TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &); + TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &); + TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &); + TIntermTyped *addSelection( + TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &); + TIntermTyped *addComma( + TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); + TIntermConstantUnion *addConstantUnion(ConstantUnion *, const TType &, const TSourceLoc &); + // TODO(zmo): Get rid of default value. + bool parseConstTree(const TSourceLoc &, TIntermNode *, ConstantUnion *, + TOperator, TType, bool singleConstantParam = false); + TIntermNode *addLoop(TLoopType, TIntermNode *, TIntermTyped *, TIntermTyped *, + TIntermNode *, const TSourceLoc &); + TIntermBranch *addBranch(TOperator, const TSourceLoc &); + TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &); + TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &); + bool postProcess(TIntermNode *); + void remove(TIntermNode *); + void outputTree(TIntermNode *); + + private: + void operator=(TIntermediate &); // prevent assignments + + TInfoSink & mInfoSink; }; -#endif // _LOCAL_INTERMEDIATE_INCLUDED_ +#endif // COMPILER_TRANSLATOR_LOCAL_INTERMEDIATE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/osinclude.h b/src/3rdparty/angle/src/compiler/translator/osinclude.h deleted file mode 100644 index cccfa6355c..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/osinclude.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2002-2010 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. -// - -#ifndef __OSINCLUDE_H -#define __OSINCLUDE_H - -// -// This file contains contains os-specific datatypes and -// declares any os-specific functions. -// - -#if defined(_WIN32) || defined(_WIN64) -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) -#define ANGLE_OS_WINRT -#else -#define ANGLE_OS_WIN -#endif -#elif defined(__APPLE__) || defined(__linux__) || \ - defined(__FreeBSD__) || defined(__OpenBSD__) || \ - defined(__NetBSD__) || defined(__DragonFly__) || \ - defined(__sun) || defined(ANDROID) || \ - defined(__GLIBC__) || defined(__GNU__) || \ - defined(__QNX__) -#define ANGLE_OS_POSIX -#else -#error Unsupported platform. -#endif - -#if defined(ANGLE_OS_WIN) || defined(ANGLE_OS_WINRT) -#define STRICT -#define VC_EXTRALEAN 1 -#include -#elif defined(ANGLE_OS_POSIX) -#include -#include -#include -#endif // ANGLE_OS_WIN - - -#include "compiler/translator/compilerdebug.h" - -// -// Thread Local Storage Operations -// -#if defined(ANGLE_OS_WIN) -typedef DWORD OS_TLSIndex; -#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES) -#elif defined(ANGLE_OS_WINRT) -typedef size_t OS_TLSIndex; -#define OS_INVALID_TLS_INDEX ((DWORD)0xFFFFFF) -#elif defined(ANGLE_OS_POSIX) -typedef pthread_key_t OS_TLSIndex; -#define OS_INVALID_TLS_INDEX (static_cast(-1)) -#endif // ANGLE_OS_WIN - -OS_TLSIndex OS_AllocTLSIndex(); -void *OS_GetTLSValue(OS_TLSIndex nIndex); -bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue); -bool OS_FreeTLSIndex(OS_TLSIndex nIndex); - -#endif // __OSINCLUDE_H diff --git a/src/3rdparty/angle/src/compiler/translator/ossource_posix.cpp b/src/3rdparty/angle/src/compiler/translator/ossource_posix.cpp deleted file mode 100644 index d4bba4c70e..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/ossource_posix.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright (c) 2002-2010 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. -// - -// -// This file contains the posix specific functions -// -#include "compiler/translator/osinclude.h" - -#if !defined(ANGLE_OS_POSIX) -#error Trying to build a posix specific file in a non-posix build. -#endif - -// -// Thread Local Storage Operations -// -OS_TLSIndex OS_AllocTLSIndex() -{ - pthread_key_t pPoolIndex; - - // - // Create global pool key. - // - if ((pthread_key_create(&pPoolIndex, NULL)) != 0) { - assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); - return false; - } - else { - return pPoolIndex; - } -} - - -void *OS_GetTLSValue(OS_TLSIndex nIndex) -{ - ASSERT(nIndex != OS_INVALID_TLS_INDEX); - - return pthread_getspecific(nIndex); -} - - -bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) -{ - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - if (pthread_setspecific(nIndex, lpvValue) == 0) - return true; - else - return false; -} - - -bool OS_FreeTLSIndex(OS_TLSIndex nIndex) -{ - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - // - // Delete the global pool key. - // - if (pthread_key_delete(nIndex) == 0) - return true; - else - return false; -} diff --git a/src/3rdparty/angle/src/compiler/translator/ossource_win.cpp b/src/3rdparty/angle/src/compiler/translator/ossource_win.cpp deleted file mode 100644 index abd8bc7833..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/ossource_win.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (c) 2002-2010 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/osinclude.h" -// -// This file contains contains the window's specific functions -// - -#if !defined(ANGLE_OS_WIN) -#error Trying to build a windows specific file in a non windows build. -#endif - - -// -// Thread Local Storage Operations -// -OS_TLSIndex OS_AllocTLSIndex() -{ - DWORD dwIndex = TlsAlloc(); - if (dwIndex == TLS_OUT_OF_INDEXES) { - assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); - return OS_INVALID_TLS_INDEX; - } - - return dwIndex; -} - - -void *OS_GetTLSValue(OS_TLSIndex nIndex) -{ - ASSERT(nIndex != OS_INVALID_TLS_INDEX); - - return TlsGetValue(nIndex); -} - - -bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) -{ - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - if (TlsSetValue(nIndex, lpvValue)) - return true; - else - return false; -} - - -bool OS_FreeTLSIndex(OS_TLSIndex nIndex) -{ - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - if (TlsFree(nIndex)) - return true; - else - return false; -} diff --git a/src/3rdparty/angle/src/compiler/translator/ossource_winrt.cpp b/src/3rdparty/angle/src/compiler/translator/ossource_winrt.cpp deleted file mode 100644 index bb061ca85d..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/ossource_winrt.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright (c) 2002-2010 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/osinclude.h" -// -// This file contains contains Windows Runtime specific functions -// - -#if !defined(ANGLE_OS_WINRT) -#error Trying to build a WinRT specific file in a non-WinRT build. -#endif - -#include - - -// -// Thread Local Storage Operations -// -__declspec(thread) std::vector *tls = nullptr; -__declspec(thread) std::vector *freeIndices = nullptr; - -OS_TLSIndex OS_AllocTLSIndex() -{ - if (!tls) - tls = new std::vector; - - if (freeIndices && !freeIndices->empty()) { - OS_TLSIndex index = freeIndices->back(); - freeIndices->pop_back(); - return index; - } else { - tls->push_back(nullptr); - return tls->size() - 1; - } -} - - -void *OS_GetTLSValue(OS_TLSIndex nIndex) -{ - ASSERT(nIndex != OS_INVALID_TLS_INDEX); - ASSERT(tls); - - return tls->at(nIndex); -} - - -bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) -{ - if (!tls || nIndex >= tls->size() || nIndex == OS_INVALID_TLS_INDEX) { - ASSERT(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - tls->at(nIndex) = lpvValue; - return true; -} - - -bool OS_FreeTLSIndex(OS_TLSIndex nIndex) -{ - if (!tls || nIndex >= tls->size() || nIndex == OS_INVALID_TLS_INDEX) { - ASSERT(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - if (!freeIndices) - freeIndices = new std::vector; - - freeIndices->push_back(nIndex); - - return true; -} diff --git a/src/3rdparty/angle/src/compiler/translator/parseConst.cpp b/src/3rdparty/angle/src/compiler/translator/parseConst.cpp index a59f0be9d8..1897ed151c 100644 --- a/src/3rdparty/angle/src/compiler/translator/parseConst.cpp +++ b/src/3rdparty/angle/src/compiler/translator/parseConst.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 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. // @@ -7,47 +7,50 @@ #include "compiler/translator/ParseContext.h" // -// Use this class to carry along data from node to node in +// Use this class to carry along data from node to node in // the traversal // -class TConstTraverser : public TIntermTraverser { -public: - TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t) +class TConstTraverser : public TIntermTraverser +{ + public: + TConstTraverser(ConstantUnion *cUnion, bool singleConstParam, + TOperator constructType, TInfoSink &sink, TType &t) : error(false), - index(0), - unionArray(cUnion), - type(t), - constructorType(constructType), - singleConstantParam(singleConstParam), - infoSink(sink), - symbolTable(symTable), - size(0), - isMatrix(false), - matrixSize(0) { + mIndex(0), + mUnionArray(cUnion), + mType(t), + mConstructorType(constructType), + mSingleConstantParam(singleConstParam), + mInfoSink(sink), + mSize(0), + mIsDiagonalMatrixInit(false), + mMatrixCols(0), + mMatrixRows(0) + { } bool error; -protected: - void visitSymbol(TIntermSymbol*); - void visitConstantUnion(TIntermConstantUnion*); - bool visitBinary(Visit visit, TIntermBinary*); - bool visitUnary(Visit visit, TIntermUnary*); - bool visitSelection(Visit visit, TIntermSelection*); - bool visitAggregate(Visit visit, TIntermAggregate*); - bool visitLoop(Visit visit, TIntermLoop*); - bool visitBranch(Visit visit, TIntermBranch*); - - size_t index; - ConstantUnion *unionArray; - TType type; - TOperator constructorType; - bool singleConstantParam; - TInfoSink& infoSink; - TSymbolTable& symbolTable; - size_t size; // size of the constructor ( 4 for vec4) - bool isMatrix; - size_t matrixSize; // dimension of the matrix (nominal size and not the instance size) + protected: + void visitSymbol(TIntermSymbol *); + void visitConstantUnion(TIntermConstantUnion *); + bool visitBinary(Visit visit, TIntermBinary *); + bool visitUnary(Visit visit, TIntermUnary *); + bool visitSelection(Visit visit, TIntermSelection *); + bool visitAggregate(Visit visit, TIntermAggregate *); + bool visitLoop(Visit visit, TIntermLoop *); + bool visitBranch(Visit visit, TIntermBranch *); + + size_t mIndex; + ConstantUnion *mUnionArray; + TType mType; + TOperator mConstructorType; + bool mSingleConstantParam; + TInfoSink &mInfoSink; + size_t mSize; // size of the constructor ( 4 for vec4) + bool mIsDiagonalMatrixInit; + int mMatrixCols; // columns of the matrix + int mMatrixRows; // rows of the matrix }; // @@ -58,169 +61,182 @@ protected: // continue on to children. If you process children yourself, // return false. // - -void TConstTraverser::visitSymbol(TIntermSymbol* node) +void TConstTraverser::visitSymbol(TIntermSymbol *node) { - infoSink.info.message(EPrefixInternalError, node->getLine(), "Symbol Node found in constant constructor"); + mInfoSink.info.message(EPrefixInternalError, node->getLine(), + "Symbol Node found in constant constructor"); return; - } -bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node) +bool TConstTraverser::visitBinary(Visit visit, TIntermBinary *node) { TQualifier qualifier = node->getType().getQualifier(); - - if (qualifier != EvqConst) { + + if (qualifier != EvqConst) + { TString buf; buf.append("'constructor' : assigning non-constant to "); - buf.append(type.getCompleteString()); - infoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); + buf.append(mType.getCompleteString()); + mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); error = true; - return false; + return false; } - infoSink.info.message(EPrefixInternalError, node->getLine(), "Binary Node found in constant constructor"); - + mInfoSink.info.message(EPrefixInternalError, node->getLine(), + "Binary Node found in constant constructor"); return false; } -bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node) +bool TConstTraverser::visitUnary(Visit visit, TIntermUnary *node) { TString buf; buf.append("'constructor' : assigning non-constant to "); - buf.append(type.getCompleteString()); - infoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); + buf.append(mType.getCompleteString()); + mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); error = true; - return false; + return false; } -bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate *node) { - if (!node->isConstructor() && node->getOp() != EOpComma) { + if (!node->isConstructor() && node->getOp() != EOpComma) + { TString buf; buf.append("'constructor' : assigning non-constant to "); - buf.append(type.getCompleteString()); - infoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); + buf.append(mType.getCompleteString()); + mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); error = true; - return false; + return false; } - if (node->getSequence().size() == 0) { + if (node->getSequence()->size() == 0) + { error = true; return false; } - bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); - if (flag) + bool flag = node->getSequence()->size() == 1 && + (*node->getSequence())[0]->getAsTyped()->getAsConstantUnion(); + if (flag) { - singleConstantParam = true; - constructorType = node->getOp(); - size = node->getType().getObjectSize(); - - if (node->getType().isMatrix()) { - isMatrix = true; - matrixSize = node->getType().getNominalSize(); + mSingleConstantParam = true; + mConstructorType = node->getOp(); + mSize = node->getType().getObjectSize(); + + if (node->getType().isMatrix()) + { + mIsDiagonalMatrixInit = true; + mMatrixCols = node->getType().getCols(); + mMatrixRows = node->getType().getRows(); } - } - - for (TIntermSequence::iterator p = node->getSequence().begin(); - p != node->getSequence().end(); p++) { + } + for (TIntermSequence::iterator p = node->getSequence()->begin(); + p != node->getSequence()->end(); p++) + { if (node->getOp() == EOpComma) - index = 0; - + mIndex = 0; (*p)->traverse(this); - } - if (flag) + } + if (flag) { - singleConstantParam = false; - constructorType = EOpNull; - size = 0; - isMatrix = false; - matrixSize = 0; + mSingleConstantParam = false; + mConstructorType = EOpNull; + mSize = 0; + mIsDiagonalMatrixInit = false; + mMatrixCols = 0; + mMatrixRows = 0; } return false; } -bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) +bool TConstTraverser::visitSelection(Visit visit, TIntermSelection *node) { - infoSink.info.message(EPrefixInternalError, node->getLine(), "Selection Node found in constant constructor"); + mInfoSink.info.message(EPrefixInternalError, node->getLine(), + "Selection Node found in constant constructor"); error = true; return false; } -void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) +void TConstTraverser::visitConstantUnion(TIntermConstantUnion *node) { if (!node->getUnionArrayPointer()) { // The constant was not initialized, this should already have been logged - assert(infoSink.info.size() != 0); + ASSERT(mInfoSink.info.size() != 0); return; } - ConstantUnion* leftUnionArray = unionArray; - size_t instanceSize = type.getObjectSize(); + ConstantUnion *leftUnionArray = mUnionArray; + size_t instanceSize = mType.getObjectSize(); + TBasicType basicType = mType.getBasicType(); - if (index >= instanceSize) + if (mIndex >= instanceSize) return; - if (!singleConstantParam) { - size_t size = node->getType().getObjectSize(); - + if (!mSingleConstantParam) + { + size_t objectSize = node->getType().getObjectSize(); ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); - for (size_t i = 0; i < size; i++) { - if (index >= instanceSize) + for (size_t i=0; i < objectSize; i++) + { + if (mIndex >= instanceSize) return; - leftUnionArray[index] = rightUnionArray[i]; - - (index)++; + leftUnionArray[mIndex].cast(basicType, rightUnionArray[i]); + mIndex++; } - } else { - size_t totalSize = index + size; + } + else + { + size_t totalSize = mIndex + mSize; ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); - if (!isMatrix) { - size_t count = 0; - for (size_t i = index; i < totalSize; i++) { + if (!mIsDiagonalMatrixInit) + { + int count = 0; + for (size_t i = mIndex; i < totalSize; i++) + { if (i >= instanceSize) return; - - leftUnionArray[i] = rightUnionArray[count]; - - (index)++; - + leftUnionArray[i].cast(basicType, rightUnionArray[count]); + mIndex++; if (node->getType().getObjectSize() > 1) count++; } - } else { // for matrix constructors - size_t count = 0; - size_t element = index; - for (size_t i = index; i < totalSize; i++) { - if (i >= instanceSize) - return; - if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 ) - leftUnionArray[i] = rightUnionArray[count]; - else - leftUnionArray[i].setFConst(0.0f); - - (index)++; - - if (node->getType().getObjectSize() > 1) - count++; + } + else + { + // for matrix diagonal constructors from a single scalar + for (int i = 0, col = 0; col < mMatrixCols; col++) + { + for (int row = 0; row < mMatrixRows; row++, i++) + { + if (col == row) + { + leftUnionArray[i].cast(basicType, rightUnionArray[0]); + } + else + { + leftUnionArray[i].setFConst(0.0f); + } + mIndex++; + } } } } } -bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) +bool TConstTraverser::visitLoop(Visit visit, TIntermLoop *node) { - infoSink.info.message(EPrefixInternalError, node->getLine(), "Loop Node found in constant constructor"); + mInfoSink.info.message(EPrefixInternalError, node->getLine(), + "Loop Node found in constant constructor"); error = true; return false; } -bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) +bool TConstTraverser::visitBranch(Visit visit, TIntermBranch *node) { - infoSink.info.message(EPrefixInternalError, node->getLine(), "Branch Node found in constant constructor"); + mInfoSink.info.message(EPrefixInternalError, node->getLine(), + "Branch Node found in constant constructor"); error = true; return false; } @@ -230,12 +246,15 @@ bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) // Individual functions can be initialized to 0 to skip processing of that // type of node. It's children will still be processed. // -bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam) +bool TIntermediate::parseConstTree( + const TSourceLoc &line, TIntermNode *root, ConstantUnion *unionArray, + TOperator constructorType, TType t, bool singleConstantParam) { if (root == 0) return false; - TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t); + TConstTraverser it(unionArray, singleConstantParam, constructorType, + mInfoSink, t); root->traverse(&it); if (it.error) diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp index a9f3f49ef3..48d44c72d1 100644 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp +++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp @@ -31,6 +31,15 @@ RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink) mSamplingOps.insert("texture2DRect(1;vf2;"); mSamplingOps.insert("texture2DRectProj(1;vf3;"); mSamplingOps.insert("texture2DRectProj(1;vf4;"); + // Sampling ops provided by EXT_shader_texture_lod. + mSamplingOps.insert("texture2DLodEXT(1;vf2;f1;"); + mSamplingOps.insert("texture2DProjLodEXT(1;vf3;f1;"); + mSamplingOps.insert("texture2DProjLodEXT(1;vf4;f1;"); + mSamplingOps.insert("textureCubeLodEXT(1;vf4;f1;"); + mSamplingOps.insert("texture2DGradEXT(1;vf2;vf2;vf2;"); + mSamplingOps.insert("texture2DProjGradEXT(1;vf3;vf2;vf2;"); + mSamplingOps.insert("texture2DProjGradEXT(1;vf4;vf2;vf2;"); + mSamplingOps.insert("textureCubeGradEXT(1;vf3;vf3;vf3;"); } // FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc. diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h index 323cb62d8a..e77d8c21cb 100644 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h +++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h @@ -7,8 +7,6 @@ #ifndef COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ #define COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ -#include "GLSLANG/ShaderLang.h" - #include "compiler/translator/intermediate.h" #include "compiler/translator/depgraph/DependencyGraph.h" diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp index ee78c35450..7c1208a298 100644 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp +++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp @@ -12,6 +12,6 @@ void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node) ++mNumErrors; mSink.message(EPrefixError, node->getLine(), - "Samplers are not permitted in vertex shaders"); + "Samplers are not permitted in vertex shaders.\n"); } } diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h index 5f0dd3197a..d461fbdbfe 100644 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h +++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h @@ -7,8 +7,6 @@ #ifndef COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ #define COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ -#include "GLSLANG/ShaderLang.h" - #include "compiler/translator/intermediate.h" #include "compiler/translator/InfoSink.h" diff --git a/src/3rdparty/angle/src/compiler/translator/util.cpp b/src/3rdparty/angle/src/compiler/translator/util.cpp index 077bdcc48b..561d4e007c 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.cpp +++ b/src/3rdparty/angle/src/compiler/translator/util.cpp @@ -9,6 +9,8 @@ #include #include "compiler/preprocessor/numeric_lex.h" +#include "common/shadervars.h" +#include "common/utilities.h" bool atof_clamp(const char *str, float *value) { @@ -26,3 +28,329 @@ bool atoi_clamp(const char *str, int *value) return success; } +namespace sh +{ + +GLenum GLVariableType(const TType &type) +{ + if (type.getBasicType() == EbtFloat) + { + if (type.isScalar()) + { + return GL_FLOAT; + } + else if (type.isVector()) + { + switch (type.getNominalSize()) + { + case 2: return GL_FLOAT_VEC2; + case 3: return GL_FLOAT_VEC3; + case 4: return GL_FLOAT_VEC4; + default: UNREACHABLE(); + } + } + else if (type.isMatrix()) + { + switch (type.getCols()) + { + case 2: + switch (type.getRows()) + { + case 2: return GL_FLOAT_MAT2; + case 3: return GL_FLOAT_MAT2x3; + case 4: return GL_FLOAT_MAT2x4; + default: UNREACHABLE(); + } + + case 3: + switch (type.getRows()) + { + case 2: return GL_FLOAT_MAT3x2; + case 3: return GL_FLOAT_MAT3; + case 4: return GL_FLOAT_MAT3x4; + default: UNREACHABLE(); + } + + case 4: + switch (type.getRows()) + { + case 2: return GL_FLOAT_MAT4x2; + case 3: return GL_FLOAT_MAT4x3; + case 4: return GL_FLOAT_MAT4; + default: UNREACHABLE(); + } + + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + else if (type.getBasicType() == EbtInt) + { + if (type.isScalar()) + { + return GL_INT; + } + else if (type.isVector()) + { + switch (type.getNominalSize()) + { + case 2: return GL_INT_VEC2; + case 3: return GL_INT_VEC3; + case 4: return GL_INT_VEC4; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + else if (type.getBasicType() == EbtUInt) + { + if (type.isScalar()) + { + return GL_UNSIGNED_INT; + } + else if (type.isVector()) + { + switch (type.getNominalSize()) + { + case 2: return GL_UNSIGNED_INT_VEC2; + case 3: return GL_UNSIGNED_INT_VEC3; + case 4: return GL_UNSIGNED_INT_VEC4; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + else if (type.getBasicType() == EbtBool) + { + if (type.isScalar()) + { + return GL_BOOL; + } + else if (type.isVector()) + { + switch (type.getNominalSize()) + { + case 2: return GL_BOOL_VEC2; + case 3: return GL_BOOL_VEC3; + case 4: return GL_BOOL_VEC4; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + + switch (type.getBasicType()) + { + case EbtSampler2D: return GL_SAMPLER_2D; + case EbtSampler3D: return GL_SAMPLER_3D; + case EbtSamplerCube: return GL_SAMPLER_CUBE; + case EbtSamplerExternalOES: return GL_SAMPLER_EXTERNAL_OES; + case EbtSampler2DRect: return GL_SAMPLER_2D_RECT_ARB; + case EbtSampler2DArray: return GL_SAMPLER_2D_ARRAY; + case EbtISampler2D: return GL_INT_SAMPLER_2D; + case EbtISampler3D: return GL_INT_SAMPLER_3D; + case EbtISamplerCube: return GL_INT_SAMPLER_CUBE; + case EbtISampler2DArray: return GL_INT_SAMPLER_2D_ARRAY; + case EbtUSampler2D: return GL_UNSIGNED_INT_SAMPLER_2D; + case EbtUSampler3D: return GL_UNSIGNED_INT_SAMPLER_3D; + case EbtUSamplerCube: return GL_UNSIGNED_INT_SAMPLER_CUBE; + case EbtUSampler2DArray: return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY; + case EbtSampler2DShadow: return GL_SAMPLER_2D_SHADOW; + case EbtSamplerCubeShadow: return GL_SAMPLER_CUBE_SHADOW; + case EbtSampler2DArrayShadow: return GL_SAMPLER_2D_ARRAY_SHADOW; + default: UNREACHABLE(); + } + + return GL_NONE; +} + +GLenum GLVariablePrecision(const TType &type) +{ + if (type.getBasicType() == EbtFloat) + { + switch (type.getPrecision()) + { + case EbpHigh: + return GL_HIGH_FLOAT; + case EbpMedium: + return GL_MEDIUM_FLOAT; + case EbpLow: + return GL_LOW_FLOAT; + case EbpUndefined: + // Should be defined as the default precision by the parser + default: + UNREACHABLE(); + } + } + else if (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt) + { + switch (type.getPrecision()) + { + case EbpHigh: + return GL_HIGH_INT; + case EbpMedium: + return GL_MEDIUM_INT; + case EbpLow: + return GL_LOW_INT; + case EbpUndefined: + // Should be defined as the default precision by the parser + default: + UNREACHABLE(); + } + } + + // Other types (boolean, sampler) don't have a precision + return GL_NONE; +} + +TString ArrayString(const TType &type) +{ + if (!type.isArray()) + { + return ""; + } + + return "[" + str(type.getArraySize()) + "]"; +} + +bool IsVaryingOut(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqVaryingOut: + case EvqInvariantVaryingOut: + case EvqSmoothOut: + case EvqFlatOut: + case EvqCentroidOut: + case EvqVertexOut: + return true; + + default: break; + } + + return false; +} + +bool IsVaryingIn(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqVaryingIn: + case EvqInvariantVaryingIn: + case EvqSmoothIn: + case EvqFlatIn: + case EvqCentroidIn: + case EvqFragmentIn: + return true; + + default: break; + } + + return false; +} + +bool IsVarying(TQualifier qualifier) +{ + return IsVaryingIn(qualifier) || IsVaryingOut(qualifier); +} + +InterpolationType GetInterpolationType(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqFlatIn: + case EvqFlatOut: + return INTERPOLATION_FLAT; + + case EvqSmoothIn: + case EvqSmoothOut: + case EvqVertexOut: + case EvqFragmentIn: + case EvqVaryingIn: + case EvqVaryingOut: + return INTERPOLATION_SMOOTH; + + case EvqCentroidIn: + case EvqCentroidOut: + return INTERPOLATION_CENTROID; + + default: UNREACHABLE(); + return INTERPOLATION_SMOOTH; + } +} + +template +void GetVariableTraverser::traverse(const TType &type, const TString &name) +{ + const TStructure *structure = type.getStruct(); + + VarT variable; + variable.name = name.c_str(); + variable.arraySize = static_cast(type.getArraySize()); + + if (!structure) + { + variable.type = GLVariableType(type); + variable.precision = GLVariablePrecision(type); + } + else + { + variable.type = GL_STRUCT_ANGLEX; + + mOutputStack.push(&variable.fields); + + const TFieldList &fields = structure->fields(); + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + TField *field = fields[fieldIndex]; + traverse(*field->type(), field->name()); + } + + mOutputStack.pop(); + } + + visitVariable(&variable); + + ASSERT(!mOutputStack.empty()); + mOutputStack.top()->push_back(variable); +} + +template +GetVariableTraverser::GetVariableTraverser(std::vector *output) +{ + ASSERT(output); + mOutputStack.push(output); +} + +template class GetVariableTraverser; +template class GetVariableTraverser; +template class GetVariableTraverser; + +GetInterfaceBlockFieldTraverser::GetInterfaceBlockFieldTraverser(std::vector *output, bool isRowMajorMatrix) + : GetVariableTraverser(output), + mIsRowMajorMatrix(isRowMajorMatrix) +{ +} + +void GetInterfaceBlockFieldTraverser::visitVariable(InterfaceBlockField *newField) +{ + if (gl::IsMatrixType(newField->type)) + { + newField->isRowMajorMatrix = mIsRowMajorMatrix; + } +} + +BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage) +{ + switch (blockStorage) + { + case EbsPacked: return BLOCKLAYOUT_PACKED; + case EbsShared: return BLOCKLAYOUT_SHARED; + case EbsStd140: return BLOCKLAYOUT_STANDARD; + default: UNREACHABLE(); return BLOCKLAYOUT_SHARED; + } +} + +} diff --git a/src/3rdparty/angle/src/compiler/translator/util.h b/src/3rdparty/angle/src/compiler/translator/util.h index dc69f39060..5c214dd4fb 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.h +++ b/src/3rdparty/angle/src/compiler/translator/util.h @@ -7,6 +7,12 @@ #ifndef COMPILER_UTIL_H #define COMPILER_UTIL_H +#include + +#include "compiler/translator/Types.h" +#include "angle_gl.h" +#include "common/shadervars.h" + // atof_clamp is like atof but // 1. it forces C locale, i.e. forcing '.' as decimal point. // 2. it clamps the value to -FLT_MAX or FLT_MAX if overflow happens. @@ -17,4 +23,44 @@ extern bool atof_clamp(const char *str, float *value); // Return false if overflow happens. extern bool atoi_clamp(const char *str, int *value); +namespace sh +{ + +GLenum GLVariableType(const TType &type); +GLenum GLVariablePrecision(const TType &type); +bool IsVaryingIn(TQualifier qualifier); +bool IsVaryingOut(TQualifier qualifier); +bool IsVarying(TQualifier qualifier); +InterpolationType GetInterpolationType(TQualifier qualifier); +BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage); +TString ArrayString(const TType &type); + +template +class GetVariableTraverser +{ + public: + GetVariableTraverser(std::vector *output); + void traverse(const TType &type, const TString &name); + + protected: + // May be overloaded + virtual void visitVariable(VarT *newVar) {} + + private: + std::stack *> mOutputStack; +}; + +struct GetInterfaceBlockFieldTraverser : public GetVariableTraverser +{ + public: + GetInterfaceBlockFieldTraverser(std::vector *output, bool isRowMajorMatrix); + + private: + virtual void visitVariable(InterfaceBlockField *newField); + + bool mIsRowMajorMatrix; +}; + +} + #endif // COMPILER_UTIL_H -- cgit v1.2.3