From a218a252c4200cfe7048de81a46f7e48349084d5 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 8 Apr 2015 17:04:36 +0300 Subject: Upgrade ANGLE to 2.1~99f075dade7c This aligns with Chromium branch 2356. This version brings more complete OpenGL ES 3 support as well as various bug fixes and performance improvements. The following changes were made to earlier patches: -0000-General-fixes-for-ANGLE-2.1 Removed. All changes are now handled elsewhere. +0001-ANGLE-Improve-Windows-Phone-support Consolidated remaining parts from 0009/0010. +0002-ANGLE-Fix-compilation-with-MinGW Remaining issues from patch 0016. +0003-ANGLE-Fix-compilation-with-MSVC2010 Remaining issues from patch 0015. +0004-ANGLE-Dynamically-load-D3D-compiler-from-list Renamed from patch 0008. +0005-ANGLE-Add-support-for-querying-platform-device Renamed from patch 0013. -0004-Make-it-possible-to-link-ANGLE-statically-for-single Removed. Fixed by adding defines to project files. -0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t Renamed to patch 0005. -0009-ANGLE-Support-WinRT Removed. Mostly fixed upstream; remaining parts in patch 0001. -0010-ANGLE-Enable-D3D11-for-feature-level-9-cards Removed. Mostly fixed upstream; remaining parts in patch 0001. -0012-ANGLE-fix-semantic-index-lookup Removed. Fixed upstream. -0013-ANGLE-Add-support-for-querying-platform-device Renamed to patch 0005. -0014-Let-ANGLE-use-multithreaded-devices-if-necessary Removed. No longer needed. -0015-ANGLE-Fix-angle-d3d11-on-MSVC2010 Moved remaining parts to patch 0003. -0016-ANGLE-Fix-compilation-with-MinGW-D3D11 Moved remaining parts to patch 0002. -0017-ANGLE-Fix-compilation-with-D3D9 Removed. Fixed upstream. -0018-ANGLE-Fix-releasing-textures-after-we-kill-D3D11 Removed. Fixed upstream. -0019-ANGLE-Fix-handling-of-shader-source-with-fixed-lengt Removed. Fixed upstream. -0020-ANGLE-Do-not-use-std-strlen Removed. Fixed upstream. -0020-ANGLE-Fix-compilation-with-MSVC2013-Update4 Removed. Fixed upstream. [ChangeLog][Third-party libraries] ANGLE was updated to Chromium branch 2356 (2.1~99f075dade7c). Change-Id: I32ccbfe95e10986bd94be7191dfd53445ea09158 Task-number: QTBUG-44815 Task-number: QTBUG-37660 Task-number: QTBUG-44694 Task-number: QTBUG-42443 Reviewed-by: Andrew Knight Reviewed-by: Friedemann Kleint --- .../src/compiler/preprocessor/DiagnosticsBase.h | 7 +- .../compiler/preprocessor/DirectiveHandlerBase.h | 7 +- .../src/compiler/preprocessor/DirectiveParser.h | 6 +- .../src/compiler/preprocessor/ExpressionParser.h | 7 +- .../src/compiler/preprocessor/ExpressionParser.y | 4 +- .../angle/src/compiler/preprocessor/Input.h | 2 +- .../angle/src/compiler/preprocessor/Lexer.h | 2 +- .../angle/src/compiler/preprocessor/Macro.h | 1 + .../src/compiler/preprocessor/MacroExpander.h | 6 +- .../angle/src/compiler/preprocessor/Preprocessor.h | 2 +- .../src/compiler/preprocessor/SourceLocation.h | 7 +- .../angle/src/compiler/preprocessor/Token.h | 1 + .../angle/src/compiler/preprocessor/Tokenizer.h | 2 +- .../angle/src/compiler/preprocessor/Tokenizer.l | 4 +- .../angle/src/compiler/preprocessor/numeric_lex.h | 7 +- .../angle/src/compiler/translator/BaseTypes.h | 49 +- .../translator/BuiltInFunctionEmulator.cpp | 415 +++------ .../compiler/translator/BuiltInFunctionEmulator.h | 112 ++- .../translator/BuiltInFunctionEmulatorGLSL.cpp | 37 + .../translator/BuiltInFunctionEmulatorGLSL.h | 19 + .../translator/BuiltInFunctionEmulatorHLSL.cpp | 410 +++++++++ .../translator/BuiltInFunctionEmulatorHLSL.h | 16 + .../angle/src/compiler/translator/CodeGen.cpp | 22 +- .../angle/src/compiler/translator/Common.h | 6 +- .../angle/src/compiler/translator/Compiler.cpp | 107 ++- .../angle/src/compiler/translator/Compiler.h | 29 +- .../angle/src/compiler/translator/ConstantUnion.h | 13 +- .../src/compiler/translator/DetectCallDepth.cpp | 6 +- .../src/compiler/translator/DetectCallDepth.h | 6 +- .../src/compiler/translator/DetectDiscontinuity.h | 6 +- .../angle/src/compiler/translator/Diagnostics.h | 9 +- .../src/compiler/translator/DirectiveHandler.cpp | 13 +- .../src/compiler/translator/DirectiveHandler.h | 13 +- .../src/compiler/translator/EmulatePrecision.cpp | 528 +++++++++++ .../src/compiler/translator/EmulatePrecision.h | 74 ++ .../src/compiler/translator/ExtensionBehavior.h | 6 +- .../src/compiler/translator/FlagStd140Structs.h | 6 +- .../angle/src/compiler/translator/ForLoopUnroll.h | 6 +- .../angle/src/compiler/translator/HashNames.h | 6 +- .../angle/src/compiler/translator/InfoSink.h | 6 +- .../angle/src/compiler/translator/Initialize.cpp | 703 ++++++--------- .../angle/src/compiler/translator/Initialize.h | 12 +- .../angle/src/compiler/translator/InitializeDll.h | 6 +- .../src/compiler/translator/InitializeGlobals.h | 6 +- .../compiler/translator/InitializeParseContext.h | 6 +- .../src/compiler/translator/InitializeVariables.h | 6 +- .../angle/src/compiler/translator/IntermNode.cpp | 311 ++++--- .../angle/src/compiler/translator/IntermNode.h | 287 ++---- .../src/compiler/translator/IntermTraverse.cpp | 54 ++ .../angle/src/compiler/translator/Intermediate.cpp | 114 +-- .../angle/src/compiler/translator/Intermediate.h | 71 ++ .../angle/src/compiler/translator/LoopInfo.h | 6 +- src/3rdparty/angle/src/compiler/translator/MMap.h | 6 +- .../angle/src/compiler/translator/NodeSearch.h | 6 +- .../angle/src/compiler/translator/Operator.cpp | 195 ++++ .../angle/src/compiler/translator/Operator.h | 226 +++++ .../angle/src/compiler/translator/OutputESSL.cpp | 23 +- .../angle/src/compiler/translator/OutputESSL.h | 11 +- .../angle/src/compiler/translator/OutputGLSL.cpp | 52 +- .../angle/src/compiler/translator/OutputGLSL.h | 13 +- .../src/compiler/translator/OutputGLSLBase.cpp | 216 ++++- .../angle/src/compiler/translator/OutputGLSLBase.h | 18 +- .../angle/src/compiler/translator/OutputHLSL.cpp | 991 +++++++++++++-------- .../angle/src/compiler/translator/OutputHLSL.h | 113 ++- .../angle/src/compiler/translator/ParseContext.cpp | 626 ++++++++++++- .../angle/src/compiler/translator/ParseContext.h | 61 +- .../angle/src/compiler/translator/PoolAlloc.h | 6 +- .../angle/src/compiler/translator/Pragma.h | 13 +- .../src/compiler/translator/QualifierAlive.cpp | 2 +- .../angle/src/compiler/translator/QualifierAlive.h | 5 + .../compiler/translator/RegenerateStructNames.h | 6 +- .../translator/RemoveSwitchFallThrough.cpp | 157 ++++ .../compiler/translator/RemoveSwitchFallThrough.h | 43 + .../angle/src/compiler/translator/RemoveTree.cpp | 29 - .../angle/src/compiler/translator/RemoveTree.h | 7 - .../angle/src/compiler/translator/RenameFunction.h | 6 +- .../src/compiler/translator/RewriteElseBlocks.h | 6 +- .../translator/ScalarizeVecAndMatConstructorArgs.h | 6 +- .../angle/src/compiler/translator/SearchSymbol.cpp | 1 - .../angle/src/compiler/translator/SearchSymbol.h | 6 +- .../angle/src/compiler/translator/ShaderLang.cpp | 16 + .../angle/src/compiler/translator/ShaderVars.cpp | 18 +- .../translator/SimplifyArrayAssignment.cpp | 38 + .../compiler/translator/SimplifyArrayAssignment.h | 25 + .../src/compiler/translator/StructureHLSL.cpp | 22 +- .../angle/src/compiler/translator/StructureHLSL.h | 14 +- .../angle/src/compiler/translator/SymbolTable.cpp | 218 +++-- .../angle/src/compiler/translator/SymbolTable.h | 70 +- .../src/compiler/translator/TranslatorESSL.cpp | 69 +- .../angle/src/compiler/translator/TranslatorESSL.h | 19 +- .../src/compiler/translator/TranslatorGLSL.cpp | 114 ++- .../angle/src/compiler/translator/TranslatorGLSL.h | 12 +- .../src/compiler/translator/TranslatorHLSL.cpp | 16 +- .../angle/src/compiler/translator/TranslatorHLSL.h | 8 +- .../angle/src/compiler/translator/Types.cpp | 18 +- src/3rdparty/angle/src/compiler/translator/Types.h | 38 +- .../src/compiler/translator/UnfoldShortCircuit.cpp | 6 +- .../src/compiler/translator/UnfoldShortCircuit.h | 9 +- .../compiler/translator/UnfoldShortCircuitAST.cpp | 28 +- .../compiler/translator/UnfoldShortCircuitAST.h | 29 +- .../angle/src/compiler/translator/UniformHLSL.cpp | 17 +- .../angle/src/compiler/translator/UniformHLSL.h | 12 +- .../angle/src/compiler/translator/UtilsHLSL.cpp | 7 + .../angle/src/compiler/translator/UtilsHLSL.h | 6 +- .../compiler/translator/ValidateLimitations.cpp | 87 -- .../src/compiler/translator/ValidateLimitations.h | 4 + .../src/compiler/translator/ValidateOutputs.h | 5 + .../src/compiler/translator/ValidateSwitch.cpp | 200 +++++ .../angle/src/compiler/translator/ValidateSwitch.h | 52 ++ .../angle/src/compiler/translator/VariableInfo.cpp | 36 +- .../angle/src/compiler/translator/VariableInfo.h | 8 +- .../angle/src/compiler/translator/VariablePacker.h | 6 +- .../angle/src/compiler/translator/VersionGLSL.cpp | 19 +- .../angle/src/compiler/translator/VersionGLSL.h | 18 +- .../angle/src/compiler/translator/blocklayout.cpp | 123 +++ .../angle/src/compiler/translator/blocklayout.h | 94 ++ .../src/compiler/translator/blocklayoutHLSL.cpp | 165 ++++ .../src/compiler/translator/blocklayoutHLSL.h | 62 ++ .../angle/src/compiler/translator/compilerdebug.h | 6 +- .../compiler/translator/depgraph/DependencyGraph.h | 8 +- .../translator/depgraph/DependencyGraphBuilder.h | 12 +- .../translator/depgraph/DependencyGraphOutput.h | 25 +- .../angle/src/compiler/translator/glslang.h | 4 + .../angle/src/compiler/translator/glslang.l | 19 +- .../angle/src/compiler/translator/glslang.y | 427 +++------ .../angle/src/compiler/translator/intermOut.cpp | 110 ++- .../angle/src/compiler/translator/intermediate.h | 67 -- .../angle/src/compiler/translator/length_limits.h | 6 +- .../timing/RestrictFragmentShaderTiming.h | 33 +- .../translator/timing/RestrictVertexShaderTiming.h | 6 +- .../angle/src/compiler/translator/util.cpp | 2 +- src/3rdparty/angle/src/compiler/translator/util.h | 10 +- 132 files changed, 6160 insertions(+), 2700 deletions(-) create mode 100644 src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h create mode 100644 src/3rdparty/angle/src/compiler/translator/Intermediate.h create mode 100644 src/3rdparty/angle/src/compiler/translator/Operator.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/Operator.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveTree.h create mode 100644 src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h create mode 100644 src/3rdparty/angle/src/compiler/translator/blocklayout.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/blocklayout.h create mode 100644 src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/intermediate.h (limited to 'src/3rdparty/angle/src/compiler') diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h index a7587ed657..5922d03857 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ -#define COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ +#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_ +#define COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_ #include @@ -84,4 +84,5 @@ class Diagnostics }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ + +#endif // COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h index eec0d5e5f0..cf67895764 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ -#define COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ +#ifndef COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_ #include @@ -41,4 +41,5 @@ class DirectiveHandler }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ + +#endif // COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h index 335091781c..e1acdbb8d0 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ -#define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ +#ifndef COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ #include "Lexer.h" #include "Macro.h" @@ -78,5 +78,5 @@ class DirectiveParser : public Lexer }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ +#endif // COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h index f040cb01fa..4b80ba7261 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ -#define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ +#ifndef COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ +#define COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ #include "pp_utils.h" @@ -31,4 +31,5 @@ class ExpressionParser }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ + +#endif // COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y index 662a31b650..8caf36bfc8 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y @@ -28,7 +28,7 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser. #pragma GCC diagnostic ignored "-Wuninitialized" #endif #elif defined(_MSC_VER) -#pragma warning(disable: 4065 4701) +#pragma warning(disable: 4065 4701 4702) #endif #include "ExpressionParser.h" @@ -69,7 +69,7 @@ struct Context %} %pure-parser -%name-prefix="pp" +%name-prefix "pp" %parse-param {Context *context} %lex-param {Context *context} diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.h b/src/3rdparty/angle/src/compiler/preprocessor/Input.h index 2ac4f0c170..e951cb4d5f 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Input.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.h @@ -58,5 +58,5 @@ class Input }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_INPUT_H_ +#endif // COMPILER_PREPROCESSOR_INPUT_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h index d42d3db7e0..990dc5e21d 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h @@ -21,5 +21,5 @@ class Lexer }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_LEXER_H_ +#endif // COMPILER_PREPROCESSOR_LEXER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h index b77e7bc15c..7662a9c5a2 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h @@ -46,4 +46,5 @@ struct Macro typedef std::map MacroSet; } // namespace pp + #endif // COMPILER_PREPROCESSOR_MACRO_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h index d4fd091786..5a0c7751a8 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ -#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ +#ifndef COMPILER_PREPROCESSOR_MACROEXPANDER_H_ +#define COMPILER_PREPROCESSOR_MACROEXPANDER_H_ #include #include @@ -85,5 +85,5 @@ class MacroExpander : public Lexer }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ +#endif // COMPILER_PREPROCESSOR_MACROEXPANDER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h index 0a55f1c9c1..fe25daa123 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h @@ -50,5 +50,5 @@ class Preprocessor }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_ +#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h index d4c1a5e178..af8a8d5d19 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ -#define COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ +#ifndef COMPILER_PREPROCESSOR_SOURCELOCATION_H_ +#define COMPILER_PREPROCESSOR_SOURCELOCATION_H_ namespace pp { @@ -43,4 +43,5 @@ inline bool operator!=(const SourceLocation &lhs, const SourceLocation &rhs) } } // namespace pp -#endif // COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ + +#endif // COMPILER_PREPROCESSOR_SOURCELOCATION_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Token.h b/src/3rdparty/angle/src/compiler/preprocessor/Token.h index 8832e279c7..347c47e307 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Token.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Token.h @@ -116,4 +116,5 @@ inline bool operator!=(const Token &lhs, const Token &rhs) 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 07ad93da05..78eb86dd3b 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h @@ -55,5 +55,5 @@ class Tokenizer : public Lexer }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_ +#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l index 2a77b905a4..89cb5c8596 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l @@ -267,7 +267,9 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") namespace pp { -Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(0) +Tokenizer::Tokenizer(Diagnostics *diagnostics) + : mHandle(0), + mMaxTokenSize(256) { mContext.diagnostics = diagnostics; } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h index 8a24540696..58c51b0961 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h @@ -6,8 +6,8 @@ // numeric_lex.h: Functions to extract numeric values from string. -#ifndef COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ -#define COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ +#ifndef COMPILER_PREPROCESSOR_NUMERICLEX_H_ +#define COMPILER_PREPROCESSOR_NUMERICLEX_H_ #include @@ -58,4 +58,5 @@ bool numeric_lex_float(const std::string &str, FloatType *value) } } // namespace pp. -#endif // COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ + +#endif // COMPILER_PREPROCESSOR_NUMERICLEX_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BaseTypes.h b/src/3rdparty/angle/src/compiler/translator/BaseTypes.h index 324b0669f4..ee1428b2d3 100644 --- a/src/3rdparty/angle/src/compiler/translator/BaseTypes.h +++ b/src/3rdparty/angle/src/compiler/translator/BaseTypes.h @@ -4,10 +4,10 @@ // found in the LICENSE file. // -#ifndef _BASICTYPES_INCLUDED_ -#define _BASICTYPES_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_BASETYPES_H_ +#define COMPILER_TRANSLATOR_BASETYPES_H_ -#include +#include "compiler/translator/compilerdebug.h" // // Precision qualifiers @@ -42,7 +42,15 @@ enum TBasicType EbtInt, EbtUInt, EbtBool, - EbtGVec4, // non type: represents vec4, ivec4 and uvec4 + EbtGVec4, // non type: represents vec4, ivec4, and uvec4 + EbtGenType, // non type: represents float, vec2, vec3, and vec4 + EbtGenIType, // non type: represents int, ivec2, ivec3, and ivec4 + EbtGenUType, // non type: represents uint, uvec2, uvec3, and uvec4 + EbtGenBType, // non type: represents bool, bvec2, bvec3, and bvec4 + EbtVec, // non type: represents vec2, vec3, and vec4 + EbtIVec, // non type: represents ivec2, ivec3, and ivec4 + EbtUVec, // non type: represents uvec2, uvec3, and uvec4 + EbtBVec, // non type: represents bvec2, bvec3, and bvec4 EbtGuardSamplerBegin, // non type: see implementation of IsSampler() EbtSampler2D, EbtSampler3D, @@ -62,10 +70,10 @@ enum TBasicType 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 + 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?? @@ -258,6 +266,11 @@ inline bool IsShadowSampler(TBasicType type) return false; } +inline bool IsInteger(TBasicType type) +{ + return type == EbtInt || type == EbtUInt; +} + inline bool SupportsPrecision(TBasicType type) { return type == EbtFloat || type == EbtInt || type == EbtUInt || IsSampler(type); @@ -293,6 +306,9 @@ enum TQualifier EvqInOut, EvqConstReadOnly, + // built-ins read by vertex shader + EvqInstanceID, + // built-ins written by vertex shader EvqPosition, EvqPointSize, @@ -307,6 +323,10 @@ enum TQualifier EvqFragData, EvqFragDepth, + // built-ins written by the shader_framebuffer_fetch extension(s) + EvqLastFragColor, + EvqLastFragData, + // GLSL ES 3.0 vertex output and fragment input EvqSmooth, // Incomplete qualifier, smooth is the default EvqFlat, // Incomplete qualifier @@ -383,6 +403,7 @@ inline const char* getQualifierString(TQualifier q) case EvqIn: return "in"; break; case EvqOut: return "out"; break; case EvqInOut: return "inout"; break; + case EvqInstanceID: return "InstanceID"; break; case EvqPosition: return "Position"; break; case EvqPointSize: return "PointSize"; break; case EvqFragCoord: return "FragCoord"; break; @@ -396,7 +417,9 @@ inline const char* getQualifierString(TQualifier q) case EvqSmoothIn: return "smooth in"; break; case EvqCentroidIn: return "centroid in"; break; case EvqFlatIn: return "flat in"; break; - default: return "unknown qualifier"; + case EvqLastFragColor: return "LastFragColor"; break; + case EvqLastFragData: return "LastFragData"; break; + default: UNREACHABLE(); return "unknown qualifier"; } } @@ -407,7 +430,7 @@ inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq) case EmpUnspecified: return "mp_unspecified"; case EmpRowMajor: return "row_major"; case EmpColumnMajor: return "column_major"; - default: return "unknown matrix packing"; + default: UNREACHABLE(); return "unknown matrix packing"; } } @@ -419,7 +442,7 @@ inline const char* getBlockStorageString(TLayoutBlockStorage bsq) case EbsShared: return "shared"; case EbsPacked: return "packed"; case EbsStd140: return "std140"; - default: return "unknown block storage"; + default: UNREACHABLE(); return "unknown block storage"; } } @@ -433,8 +456,8 @@ inline const char* getInterpolationString(TQualifier q) case EvqSmoothIn: return "smooth"; break; case EvqCentroidIn: return "centroid"; break; case EvqFlatIn: return "flat"; break; - default: return "unknown interpolation"; + default: UNREACHABLE(); return "unknown interpolation"; } } -#endif // _BASICTYPES_INCLUDED_ +#endif // COMPILER_TRANSLATOR_BASETYPES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp index 0e8239cc1e..51461207c5 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp @@ -8,193 +8,9 @@ #include "compiler/translator/BuiltInFunctionEmulator.h" #include "compiler/translator/SymbolTable.h" -namespace { - -// we use macros here instead of function definitions to work around more GLSL -// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are -// problematic because if the argument has side-effects they will be repeatedly -// evaluated. This is unlikely to show up in real shaders, but is something to -// consider. -const char* kFunctionEmulationVertexSource[] = { - "#error no emulation for cos(float)", - "#error no emulation for cos(vec2)", - "#error no emulation for cos(vec3)", - "#error no emulation for cos(vec4)", - - "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))", - "#error no emulation for distance(vec2, vec2)", - "#error no emulation for distance(vec3, vec3)", - "#error no emulation for distance(vec4, vec4)", - - "#define webgl_dot_emu(x, y) ((x) * (y))", - "#error no emulation for dot(vec2, vec2)", - "#error no emulation for dot(vec3, vec3)", - "#error no emulation for dot(vec4, vec4)", - - "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))", - "#error no emulation for length(vec2)", - "#error no emulation for length(vec3)", - "#error no emulation for length(vec4)", - - "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))", - "#error no emulation for normalize(vec2)", - "#error no emulation for normalize(vec3)", - "#error no emulation for normalize(vec4)", - - "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))", - "#error no emulation for reflect(vec2, vec2)", - "#error no emulation for reflect(vec3, vec3)", - "#error no emulation for reflect(vec4, vec4)" -}; - -const char* kFunctionEmulationFragmentSource[] = { - "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }", - "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }", - "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }", - "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }", - - "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))", - "#error no emulation for distance(vec2, vec2)", - "#error no emulation for distance(vec3, vec3)", - "#error no emulation for distance(vec4, vec4)", - - "#define webgl_dot_emu(x, y) ((x) * (y))", - "#error no emulation for dot(vec2, vec2)", - "#error no emulation for dot(vec3, vec3)", - "#error no emulation for dot(vec4, vec4)", - - "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))", - "#error no emulation for length(vec2)", - "#error no emulation for length(vec3)", - "#error no emulation for length(vec4)", - - "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))", - "#error no emulation for normalize(vec2)", - "#error no emulation for normalize(vec3)", - "#error no emulation for normalize(vec4)", - - "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))", - "#error no emulation for reflect(vec2, vec2)", - "#error no emulation for reflect(vec3, vec3)", - "#error no emulation for reflect(vec4, vec4)" -}; - -const bool kFunctionEmulationVertexMask[] = { -#if defined(__APPLE__) - // Work around ATI driver bugs in Mac. - false, // TFunctionCos1 - false, // TFunctionCos2 - false, // TFunctionCos3 - false, // TFunctionCos4 - true, // TFunctionDistance1_1 - false, // TFunctionDistance2_2 - false, // TFunctionDistance3_3 - false, // TFunctionDistance4_4 - true, // TFunctionDot1_1 - false, // TFunctionDot2_2 - false, // TFunctionDot3_3 - false, // TFunctionDot4_4 - true, // TFunctionLength1 - false, // TFunctionLength2 - false, // TFunctionLength3 - false, // TFunctionLength4 - true, // TFunctionNormalize1 - false, // TFunctionNormalize2 - false, // TFunctionNormalize3 - false, // TFunctionNormalize4 - true, // TFunctionReflect1_1 - false, // TFunctionReflect2_2 - false, // TFunctionReflect3_3 - false, // TFunctionReflect4_4 -#else - // Work around D3D driver bug in Win. - false, // TFunctionCos1 - false, // TFunctionCos2 - false, // TFunctionCos3 - false, // TFunctionCos4 - false, // TFunctionDistance1_1 - false, // TFunctionDistance2_2 - false, // TFunctionDistance3_3 - false, // TFunctionDistance4_4 - false, // TFunctionDot1_1 - false, // TFunctionDot2_2 - false, // TFunctionDot3_3 - false, // TFunctionDot4_4 - false, // TFunctionLength1 - false, // TFunctionLength2 - false, // TFunctionLength3 - false, // TFunctionLength4 - false, // TFunctionNormalize1 - false, // TFunctionNormalize2 - false, // TFunctionNormalize3 - false, // TFunctionNormalize4 - false, // TFunctionReflect1_1 - false, // TFunctionReflect2_2 - false, // TFunctionReflect3_3 - false, // TFunctionReflect4_4 -#endif - false // TFunctionUnknown -}; - -const bool kFunctionEmulationFragmentMask[] = { -#if defined(__APPLE__) - // Work around ATI driver bugs in Mac. - true, // TFunctionCos1 - true, // TFunctionCos2 - true, // TFunctionCos3 - true, // TFunctionCos4 - true, // TFunctionDistance1_1 - false, // TFunctionDistance2_2 - false, // TFunctionDistance3_3 - false, // TFunctionDistance4_4 - true, // TFunctionDot1_1 - false, // TFunctionDot2_2 - false, // TFunctionDot3_3 - false, // TFunctionDot4_4 - true, // TFunctionLength1 - false, // TFunctionLength2 - false, // TFunctionLength3 - false, // TFunctionLength4 - true, // TFunctionNormalize1 - false, // TFunctionNormalize2 - false, // TFunctionNormalize3 - false, // TFunctionNormalize4 - true, // TFunctionReflect1_1 - false, // TFunctionReflect2_2 - false, // TFunctionReflect3_3 - false, // TFunctionReflect4_4 -#else - // Work around D3D driver bug in Win. - false, // TFunctionCos1 - false, // TFunctionCos2 - false, // TFunctionCos3 - false, // TFunctionCos4 - false, // TFunctionDistance1_1 - false, // TFunctionDistance2_2 - false, // TFunctionDistance3_3 - false, // TFunctionDistance4_4 - false, // TFunctionDot1_1 - false, // TFunctionDot2_2 - false, // TFunctionDot3_3 - false, // TFunctionDot4_4 - false, // TFunctionLength1 - false, // TFunctionLength2 - false, // TFunctionLength3 - false, // TFunctionLength4 - false, // TFunctionNormalize1 - false, // TFunctionNormalize2 - false, // TFunctionNormalize3 - false, // TFunctionNormalize4 - false, // TFunctionReflect1_1 - false, // TFunctionReflect2_2 - false, // TFunctionReflect3_3 - false, // TFunctionReflect4_4 -#endif - false // TFunctionUnknown -}; - -class BuiltInFunctionEmulationMarker : public TIntermTraverser { -public: +class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser +{ + public: BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator) : mEmulator(emulator) { @@ -238,148 +54,119 @@ public: case EOpFaceForward: case EOpReflect: case EOpRefract: + case EOpOuterProduct: case EOpMul: break; default: return true; }; const TIntermSequence& sequence = *(node->getSequence()); - // Right now we only handle built-in functions with two parameters. - if (sequence.size() != 2) - return true; - TIntermTyped* param1 = sequence[0]->getAsTyped(); - TIntermTyped* param2 = sequence[1]->getAsTyped(); - if (!param1 || !param2) + bool needToEmulate = false; + // Right now we only handle built-in functions with two or three parameters. + if (sequence.size() == 2) + { + TIntermTyped* param1 = sequence[0]->getAsTyped(); + TIntermTyped* param2 = sequence[1]->getAsTyped(); + if (!param1 || !param2) + return true; + needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), param1->getType(), param2->getType()); + } + else if (sequence.size() == 3) + { + TIntermTyped* param1 = sequence[0]->getAsTyped(); + TIntermTyped* param2 = sequence[1]->getAsTyped(); + TIntermTyped* param3 = sequence[2]->getAsTyped(); + if (!param1 || !param2 || !param3) + return true; + needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), param1->getType(), param2->getType(), param3->getType()); + } + else + { return true; - bool needToEmulate = mEmulator.SetFunctionCalled( - node->getOp(), param1->getType(), param2->getType()); + } + if (needToEmulate) node->setUseEmulatedFunction(); } return true; } -private: + private: BuiltInFunctionEmulator& mEmulator; }; -} // anonymous namepsace +BuiltInFunctionEmulator::BuiltInFunctionEmulator() +{} -BuiltInFunctionEmulator::BuiltInFunctionEmulator(sh::GLenum shaderType) +void BuiltInFunctionEmulator::addEmulatedFunction( + TOperator op, const TType& param, + const char* emulatedFunctionDefinition) { - if (shaderType == GL_FRAGMENT_SHADER) { - mFunctionMask = kFunctionEmulationFragmentMask; - mFunctionSource = kFunctionEmulationFragmentSource; - } else { - mFunctionMask = kFunctionEmulationVertexMask; - mFunctionSource = kFunctionEmulationVertexSource; - } + mEmulatedFunctions[FunctionId(op, param)] = + std::string(emulatedFunctionDefinition); } -bool BuiltInFunctionEmulator::SetFunctionCalled( - TOperator op, const TType& param) +void BuiltInFunctionEmulator::addEmulatedFunction( + TOperator op, const TType& param1, const TType& param2, + const char* emulatedFunctionDefinition) { - TBuiltInFunction function = IdentifyFunction(op, param); - return SetFunctionCalled(function); + mEmulatedFunctions[FunctionId(op, param1, param2)] = + std::string(emulatedFunctionDefinition); } -bool BuiltInFunctionEmulator::SetFunctionCalled( - TOperator op, const TType& param1, const TType& param2) +void BuiltInFunctionEmulator::addEmulatedFunction( + TOperator op, const TType& param1, const TType& param2, const TType& param3, + const char* emulatedFunctionDefinition) { - TBuiltInFunction function = IdentifyFunction(op, param1, param2); - return SetFunctionCalled(function); + mEmulatedFunctions[FunctionId(op, param1, param2, param3)] = + std::string(emulatedFunctionDefinition); } -bool BuiltInFunctionEmulator::SetFunctionCalled( - BuiltInFunctionEmulator::TBuiltInFunction function) { - if (function == TFunctionUnknown || mFunctionMask[function] == false) - return false; - for (size_t i = 0; i < mFunctions.size(); ++i) { - if (mFunctions[i] == function) - return true; - } - mFunctions.push_back(function); - return true; +bool BuiltInFunctionEmulator::IsOutputEmpty() const +{ + return (mFunctions.size() == 0); } -void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition( - TInfoSinkBase& out, bool withPrecision) const +void BuiltInFunctionEmulator::OutputEmulatedFunctions( + TInfoSinkBase& out) const { - if (mFunctions.size() == 0) - return; - out << "// BEGIN: Generated code for built-in function emulation\n\n"; - if (withPrecision) { - out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n" - << "#define webgl_emu_precision highp\n" - << "#else\n" - << "#define webgl_emu_precision mediump\n" - << "#endif\n\n"; - } else { - out << "#define webgl_emu_precision\n\n"; - } for (size_t i = 0; i < mFunctions.size(); ++i) { - out << mFunctionSource[mFunctions[i]] << "\n\n"; + out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n"; } - out << "// END: Generated code for built-in function emulation\n\n"; } -BuiltInFunctionEmulator::TBuiltInFunction -BuiltInFunctionEmulator::IdentifyFunction( +bool BuiltInFunctionEmulator::SetFunctionCalled( TOperator op, const TType& param) { - if (param.getNominalSize() > 4 || param.getSecondarySize() > 4) - return TFunctionUnknown; - unsigned int function = TFunctionUnknown; - switch (op) { - case EOpCos: - function = TFunctionCos1; - break; - case EOpLength: - function = TFunctionLength1; - break; - case EOpNormalize: - function = TFunctionNormalize1; - break; - default: - break; - } - if (function == TFunctionUnknown) - return TFunctionUnknown; - if (param.isVector()) - function += param.getNominalSize() - 1; - return static_cast(function); + return SetFunctionCalled(FunctionId(op, param)); } -BuiltInFunctionEmulator::TBuiltInFunction -BuiltInFunctionEmulator::IdentifyFunction( +bool BuiltInFunctionEmulator::SetFunctionCalled( TOperator op, const TType& param1, const TType& param2) { - // Right now for all the emulated functions with two parameters, the two - // parameters have the same type. - if (param1.getNominalSize() != param2.getNominalSize() || - param1.getSecondarySize() != param2.getSecondarySize() || - param1.getNominalSize() > 4 || param1.getSecondarySize() > 4) - return TFunctionUnknown; + return SetFunctionCalled(FunctionId(op, param1, param2)); +} + +bool BuiltInFunctionEmulator::SetFunctionCalled( + TOperator op, const TType& param1, const TType& param2, const TType& param3) +{ + return SetFunctionCalled(FunctionId(op, param1, param2, param3)); +} - unsigned int function = TFunctionUnknown; - switch (op) { - case EOpDistance: - function = TFunctionDistance1_1; - break; - case EOpDot: - function = TFunctionDot1_1; - break; - case EOpReflect: - function = TFunctionReflect1_1; - break; - default: - break; +bool BuiltInFunctionEmulator::SetFunctionCalled( + const FunctionId& functionId) { + if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end()) + { + for (size_t i = 0; i < mFunctions.size(); ++i) { + if (mFunctions[i] == functionId) + return true; + } + mFunctions.push_back(functionId); + return true; } - if (function == TFunctionUnknown) - return TFunctionUnknown; - if (param1.isVector()) - function += param1.getNominalSize() - 1; - return static_cast(function); + return false; } void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation( @@ -387,6 +174,9 @@ void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation( { ASSERT(root); + if (mEmulatedFunctions.empty()) + return; + BuiltInFunctionEmulationMarker marker(*this); root->traverse(&marker); } @@ -404,3 +194,52 @@ TString BuiltInFunctionEmulator::GetEmulatedFunctionName( return "webgl_" + name.substr(0, name.length() - 1) + "_emu("; } +BuiltInFunctionEmulator::FunctionId::FunctionId + (TOperator op, const TType& param) + : mOp(op), + mParam1(param), + mParam2(EbtVoid), + mParam3(EbtVoid) +{ +} + +BuiltInFunctionEmulator::FunctionId::FunctionId + (TOperator op, const TType& param1, const TType& param2) + : mOp(op), + mParam1(param1), + mParam2(param2), + mParam3(EbtVoid) +{ +} + +BuiltInFunctionEmulator::FunctionId::FunctionId + (TOperator op, const TType& param1, const TType& param2, const TType& param3) + : mOp(op), + mParam1(param1), + mParam2(param2), + mParam3(param3) +{ +} + +bool BuiltInFunctionEmulator::FunctionId::operator== + (const BuiltInFunctionEmulator::FunctionId& other) const +{ + return (mOp == other.mOp && + mParam1 == other.mParam1 && + mParam2 == other.mParam2 && + mParam3 == other.mParam3); +} + +bool BuiltInFunctionEmulator::FunctionId::operator< + (const BuiltInFunctionEmulator::FunctionId& other) const +{ + if (mOp != other.mOp) + return mOp < other.mOp; + if (mParam1 != other.mParam1) + return mParam1 < other.mParam1; + if (mParam2 != other.mParam2) + return mParam2 < other.mParam2; + if (mParam3 != other.mParam3) + return mParam3 < other.mParam3; + return false; // all fields are equal +} diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h index c6bf77c386..df556985e1 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ -#define COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ +#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_ +#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_ #include "compiler/translator/InfoSink.h" #include "compiler/translator/IntermNode.h" @@ -13,23 +13,13 @@ // // This class decides which built-in functions need to be replaced with the // emulated ones. -// It's only a workaround for OpenGL driver bugs, and isn't needed in general. +// It can be used to work around driver bugs or implement functions that are +// not natively implemented on a specific platform. // -class BuiltInFunctionEmulator { -public: - 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. - // Returns true if the function call needs to be replaced with an emulated - // one. - bool SetFunctionCalled(TOperator op, const TType& param); - bool SetFunctionCalled( - TOperator op, const TType& param1, const TType& param2); - - // Output function emulation definition. This should be before any other - // shader source. - void OutputEmulatedFunctionDefinition(TInfoSinkBase& out, bool withPrecision) const; +class BuiltInFunctionEmulator +{ + public: + BuiltInFunctionEmulator(); void MarkBuiltInFunctionsForEmulation(TIntermNode* root); @@ -38,54 +28,52 @@ public: // "name(" becomes "webgl_name_emu(". static TString GetEmulatedFunctionName(const TString& name); -private: - // - // Built-in functions. - // - enum TBuiltInFunction { - TFunctionCos1 = 0, // float cos(float); - TFunctionCos2, // vec2 cos(vec2); - TFunctionCos3, // vec3 cos(vec3); - TFunctionCos4, // vec4 cos(vec4); - - TFunctionDistance1_1, // float distance(float, float); - TFunctionDistance2_2, // vec2 distance(vec2, vec2); - TFunctionDistance3_3, // vec3 distance(vec3, vec3); - TFunctionDistance4_4, // vec4 distance(vec4, vec4); - - TFunctionDot1_1, // float dot(float, float); - TFunctionDot2_2, // vec2 dot(vec2, vec2); - TFunctionDot3_3, // vec3 dot(vec3, vec3); - TFunctionDot4_4, // vec4 dot(vec4, vec4); - - TFunctionLength1, // float length(float); - TFunctionLength2, // float length(vec2); - TFunctionLength3, // float length(vec3); - TFunctionLength4, // float length(vec4); - - TFunctionNormalize1, // float normalize(float); - TFunctionNormalize2, // vec2 normalize(vec2); - TFunctionNormalize3, // vec3 normalize(vec3); - TFunctionNormalize4, // vec4 normalize(vec4); - - TFunctionReflect1_1, // float reflect(float, float); - TFunctionReflect2_2, // vec2 reflect(vec2, vec2); - TFunctionReflect3_3, // vec3 reflect(vec3, vec3); - TFunctionReflect4_4, // vec4 reflect(vec4, vec4); - - TFunctionUnknown - }; + bool IsOutputEmpty() const; + + // Output function emulation definition. This should be before any other + // shader source. + void OutputEmulatedFunctions(TInfoSinkBase& out) const; + + // Add functions that need to be emulated. + void addEmulatedFunction(TOperator op, const TType& param, const char* emulatedFunctionDefinition); + void addEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const char* emulatedFunctionDefinition); + void addEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const TType& param3, const char* emulatedFunctionDefinition); - TBuiltInFunction IdentifyFunction(TOperator op, const TType& param); - TBuiltInFunction IdentifyFunction( + private: + class BuiltInFunctionEmulationMarker; + + // Records that a function is called by the shader and might need to be + // emulated. If the function is not in mEmulatedFunctions, this becomes a + // no-op. Returns true if the function call needs to be replaced with an + // emulated one. + bool SetFunctionCalled(TOperator op, const TType& param); + bool SetFunctionCalled( TOperator op, const TType& param1, const TType& param2); + bool SetFunctionCalled( + TOperator op, const TType& param1, const TType& param2, const TType& param3); + + class FunctionId { + public: + FunctionId(TOperator op, const TType& param); + FunctionId(TOperator op, const TType& param1, const TType& param2); + FunctionId(TOperator op, const TType& param1, const TType& param2, const TType& param3); + + bool operator==(const FunctionId& other) const; + bool operator<(const FunctionId& other) const; + private: + TOperator mOp; + TType mParam1; + TType mParam2; + TType mParam3; + }; - bool SetFunctionCalled(TBuiltInFunction function); + bool SetFunctionCalled(const FunctionId& functionId); - std::vector mFunctions; + // Map from function id to emulated function definition + std::map mEmulatedFunctions; - const bool* mFunctionMask; // a boolean flag for each function. - const char** mFunctionSource; + // Called function ids + std::vector mFunctions; }; -#endif // COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ +#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp new file mode 100644 index 0000000000..9de99831ad --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2002-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. +// + +#include "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h" +#include "compiler/translator/SymbolTable.h" + +void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType) +{ + // we use macros here instead of function definitions to work around more GLSL + // compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are + // problematic because if the argument has side-effects they will be repeatedly + // evaluated. This is unlikely to show up in real shaders, but is something to + // consider. + + TType float1(EbtFloat); + TType float2(EbtFloat, 2); + TType float3(EbtFloat, 3); + TType float4(EbtFloat, 4); + + if (shaderType == GL_FRAGMENT_SHADER) + { + emu->addEmulatedFunction(EOpCos, float1, "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }"); + emu->addEmulatedFunction(EOpCos, float2, "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }"); + emu->addEmulatedFunction(EOpCos, float3, "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }"); + emu->addEmulatedFunction(EOpCos, float4, "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }"); + } + emu->addEmulatedFunction(EOpDistance, float1, float1, "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))"); + emu->addEmulatedFunction(EOpDot, float1, float1, "#define webgl_dot_emu(x, y) ((x) * (y))"); + emu->addEmulatedFunction(EOpLength, float1, "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))"); + emu->addEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))"); + emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))"); +} diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h new file mode 100644 index 0000000000..5707a4b35a --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h @@ -0,0 +1,19 @@ +// +// 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. +// + +#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_ +#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_ + +#include "GLSLANG/ShaderLang.h" + +class BuiltInFunctionEmulator; + +// +// This is only a workaround for OpenGL driver bugs, and isn't needed in general. +// +void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType); + +#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp new file mode 100644 index 0000000000..7123a0d5c0 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp @@ -0,0 +1,410 @@ +// +// 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. +// + +#include "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" +#include "compiler/translator/SymbolTable.h" + +void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu) +{ + TType float1(EbtFloat); + TType float2(EbtFloat, 2); + TType float3(EbtFloat, 3); + TType float4(EbtFloat, 4); + + emu->addEmulatedFunction(EOpMod, float1, float1, + "float webgl_mod_emu(float x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float2, float2, + "float2 webgl_mod_emu(float2 x, float2 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float2, float1, + "float2 webgl_mod_emu(float2 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float3, float3, + "float3 webgl_mod_emu(float3 x, float3 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float3, float1, + "float3 webgl_mod_emu(float3 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float4, float4, + "float4 webgl_mod_emu(float4 x, float4 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float4, float1, + "float4 webgl_mod_emu(float4 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + + emu->addEmulatedFunction(EOpFaceForward, float1, float1, float1, + "float webgl_faceforward_emu(float N, float I, float Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpFaceForward, float2, float2, float2, + "float2 webgl_faceforward_emu(float2 N, float2 I, float2 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpFaceForward, float3, float3, float3, + "float3 webgl_faceforward_emu(float3 N, float3 I, float3 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpFaceForward, float4, float4, float4, + "float4 webgl_faceforward_emu(float4 N, float4 I, float4 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"); + + emu->addEmulatedFunction(EOpAtan, float1, float1, + "float webgl_atan_emu(float y, float x)\n" + "{\n" + " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN + " return atan2(y, x);\n" + "}\n"); + emu->addEmulatedFunction(EOpAtan, float2, float2, + "float2 webgl_atan_emu(float2 y, float2 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n" + "}\n"); + emu->addEmulatedFunction(EOpAtan, float3, float3, + "float3 webgl_atan_emu(float3 y, float3 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n" + "}\n"); + emu->addEmulatedFunction(EOpAtan, float4, float4, + "float4 webgl_atan_emu(float4 y, float4 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n" + " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n" + "}\n"); + + emu->addEmulatedFunction(EOpAsinh, float1, + "float webgl_asinh_emu(in float x) {\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAsinh, float2, + "float2 webgl_asinh_emu(in float2 x) {\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAsinh, float3, + "float3 webgl_asinh_emu(in float3 x) {\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAsinh, float4, + "float4 webgl_asinh_emu(in float4 x) {\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"); + + emu->addEmulatedFunction(EOpAcosh, float1, + "float webgl_acosh_emu(in float x) {\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAcosh, float2, + "float2 webgl_acosh_emu(in float2 x) {\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAcosh, float3, + "float3 webgl_acosh_emu(in float3 x) {\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAcosh, float4, + "float4 webgl_acosh_emu(in float4 x) {\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"); + + emu->addEmulatedFunction(EOpAtanh, float1, + "float webgl_atanh_emu(in float x) {\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"); + emu->addEmulatedFunction(EOpAtanh, float2, + "float2 webgl_atanh_emu(in float2 x) {\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"); + emu->addEmulatedFunction(EOpAtanh, float3, + "float3 webgl_atanh_emu(in float3 x) {\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"); + emu->addEmulatedFunction(EOpAtanh, float4, + "float4 webgl_atanh_emu(in float4 x) {\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"); + + emu->addEmulatedFunction(EOpRoundEven, float1, + "float webgl_roundEven_emu(in float x) {\n" + " return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n" + "}\n"); + emu->addEmulatedFunction(EOpRoundEven, float2, + "float2 webgl_roundEven_emu(in float2 x) {\n" + " float2 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " return v;\n" + "}\n"); + emu->addEmulatedFunction(EOpRoundEven, float3, + "float3 webgl_roundEven_emu(in float3 x) {\n" + " float3 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" + " return v;\n" + "}\n"); + emu->addEmulatedFunction(EOpRoundEven, float4, + "float4 webgl_roundEven_emu(in float4 x) {\n" + " float4 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" + " v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);\n" + " return v;\n" + "}\n"); + + emu->addEmulatedFunction(EOpPackSnorm2x16, float2, + "int webgl_toSnorm(in float x) {\n" + " return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n" + "}\n" + "\n" + "uint webgl_packSnorm2x16_emu(in float2 v) {\n" + " int x = webgl_toSnorm(v.x);\n" + " int y = webgl_toSnorm(v.y);\n" + " return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n" + "}\n"); + emu->addEmulatedFunction(EOpPackUnorm2x16, float2, + "uint webgl_toUnorm(in float x) {\n" + " return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n" + "}\n" + "\n" + "uint webgl_packUnorm2x16_emu(in float2 v) {\n" + " uint x = webgl_toUnorm(v.x);\n" + " uint y = webgl_toUnorm(v.y);\n" + " return (y << 16) | x;\n" + "}\n"); + emu->addEmulatedFunction(EOpPackHalf2x16, float2, + "uint webgl_packHalf2x16_emu(in float2 v) {\n" + " uint x = f32tof16(v.x);\n" + " uint y = f32tof16(v.y);\n" + " return (y << 16) | x;\n" + "}\n"); + + TType uint1(EbtUInt); + + emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1, + "float webgl_fromSnorm(in uint x) {\n" + " int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n" + " return clamp(float(xi) / 32767.0, -1.0, 1.0);\n" + "}\n" + "\n" + "float2 webgl_unpackSnorm2x16_emu(in uint u) {\n" + " uint y = (u >> 16);\n" + " uint x = u;\n" + " return float2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n" + "}\n"); + emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1, + "float webgl_fromUnorm(in uint x) {\n" + " return float(x) / 65535.0;\n" + "}\n" + "\n" + "float2 webgl_unpackUnorm2x16_emu(in uint u) {\n" + " uint y = (u >> 16);\n" + " uint x = u & 0xffffu;\n" + " return float2(webgl_fromUnorm(x), webgl_fromUnorm(y));\n" + "}\n"); + emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1, + "float2 webgl_unpackHalf2x16_emu(in uint u) {\n" + " uint y = (u >> 16);\n" + " uint x = u & 0xffffu;\n" + " return float2(f16tof32(x), f16tof32(y));\n" + "}\n"); + + // The matrix resulting from outer product needs to be transposed + // (matrices are stored as transposed to simplify element access in HLSL). + // So the function should return transpose(c * r) where c is a column vector + // and r is a row vector. This can be simplified by using the following + // formula: + // transpose(c * r) = transpose(r) * transpose(c) + // transpose(r) and transpose(c) are in a sense free, since to get the + // transpose of r, we simply can build a column matrix out of the original + // vector instead of a row matrix. + emu->addEmulatedFunction(EOpOuterProduct, float2, float2, + "float2x2 webgl_outerProduct_emu(in float2 c, in float2 r) {\n" + " return mul(float2x1(r), float1x2(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float3, float3, + "float3x3 webgl_outerProduct_emu(in float3 c, in float3 r) {\n" + " return mul(float3x1(r), float1x3(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float4, float4, + "float4x4 webgl_outerProduct_emu(in float4 c, in float4 r) {\n" + " return mul(float4x1(r), float1x4(c));\n" + "}\n"); + + emu->addEmulatedFunction(EOpOuterProduct, float3, float2, + "float2x3 webgl_outerProduct_emu(in float3 c, in float2 r) {\n" + " return mul(float2x1(r), float1x3(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float2, float3, + "float3x2 webgl_outerProduct_emu(in float2 c, in float3 r) {\n" + " return mul(float3x1(r), float1x2(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float4, float2, + "float2x4 webgl_outerProduct_emu(in float4 c, in float2 r) {\n" + " return mul(float2x1(r), float1x4(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float2, float4, + "float4x2 webgl_outerProduct_emu(in float2 c, in float4 r) {\n" + " return mul(float4x1(r), float1x2(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float4, float3, + "float3x4 webgl_outerProduct_emu(in float4 c, in float3 r) {\n" + " return mul(float3x1(r), float1x4(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float3, float4, + "float4x3 webgl_outerProduct_emu(in float3 c, in float4 r) {\n" + " return mul(float4x1(r), float1x3(c));\n" + "}\n"); + + TType mat2(EbtFloat, 2, 2); + TType mat3(EbtFloat, 3, 3); + TType mat4(EbtFloat, 4, 4); + + // Remember here that the parameter matrix is actually the transpose + // of the matrix that we're trying to invert, and the resulting matrix + // should also be the transpose of the inverse. + + // When accessing the parameter matrix with m[a][b] it can be thought of so + // that a is the column and b is the row of the matrix that we're inverting. + + // We calculate the inverse as the adjugate matrix divided by the + // determinant of the matrix being inverted. However, as the result needs + // to be transposed, we actually use of the transpose of the adjugate matrix + // which happens to be the cofactor matrix. That's stored in "cof". + + // We don't need to care about divide-by-zero since results are undefined + // for singular or poorly-conditioned matrices. + + emu->addEmulatedFunction(EOpInverse, mat2, + "float2x2 webgl_inverse_emu(in float2x2 m) {\n" + " float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };\n" + " return cof / determinant(transpose(m));\n" + "}\n"); + + // cofAB is the cofactor for column A and row B. + + emu->addEmulatedFunction(EOpInverse, mat3, + "float3x3 webgl_inverse_emu(in float3x3 m) {\n" + " float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n" + " float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n" + " float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n" + " float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n" + " float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];\n" + " float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n" + " float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];\n" + " float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n" + " float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];\n" + " float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };\n" + " return cof / determinant(transpose(m));\n" + "}\n"); + + emu->addEmulatedFunction(EOpInverse, mat4, + "float4x4 webgl_inverse_emu(in float4x4 m) {\n" + " float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * m[1][2] * m[2][3]" + " - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * m[1][3];\n" + " float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * m[1][2] * m[2][3]" + " - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * m[1][3]);\n" + " float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * m[1][1] * m[2][3]" + " - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * m[1][3];\n" + " float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * m[1][1] * m[2][2]" + " - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * m[1][2]);\n" + " float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * m[0][2] * m[2][3]" + " - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * m[0][3]);\n" + " float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * m[0][2] * m[2][3]" + " - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * m[0][3];\n" + " float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * m[0][1] * m[2][3]" + " - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * m[0][3]);\n" + " float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * m[0][1] * m[2][2]" + " - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * m[0][2];\n" + " float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * m[0][2] * m[1][3]" + " - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * m[0][3];\n" + " float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * m[0][2] * m[1][3]" + " - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * m[0][3]);\n" + " float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * m[0][1] * m[1][3]" + " - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * m[0][3];\n" + " float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * m[0][1] * m[1][2]" + " - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * m[0][2]);\n" + " float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * m[0][2] * m[1][3]" + " - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * m[0][3]);\n" + " float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * m[0][2] * m[1][3]" + " - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * m[0][3];\n" + " float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * m[0][1] * m[1][3]" + " - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * m[0][3]);\n" + " float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * m[0][1] * m[1][2]" + " - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * m[0][2];\n" + " float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31," + " cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n" + " return cof / determinant(transpose(m));\n" + "}\n"); +} diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h new file mode 100644 index 0000000000..4c45a93dc4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h @@ -0,0 +1,16 @@ +// +// 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. +// + +#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ +#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ + +#include "GLSLANG/ShaderLang.h" + +class BuiltInFunctionEmulator; + +void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu); + +#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp index 71056f4297..5e3eb1cc05 100644 --- a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp +++ b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp @@ -6,7 +6,9 @@ #include "compiler/translator/TranslatorESSL.h" #include "compiler/translator/TranslatorGLSL.h" +#ifdef ANGLE_ENABLE_HLSL #include "compiler/translator/TranslatorHLSL.h" +#endif // ANGLE_ENABLE_HLSL // // This function must be provided to create the actual @@ -17,14 +19,22 @@ TCompiler* ConstructCompiler( 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: - return new TranslatorGLSL(type, spec); - case SH_HLSL9_OUTPUT: - case SH_HLSL11_OUTPUT: + case SH_GLSL_CORE_OUTPUT: + case SH_GLSL_COMPATIBILITY_OUTPUT: + return new TranslatorGLSL(type, spec, output); + case SH_HLSL9_OUTPUT: + case SH_HLSL11_OUTPUT: +#ifdef ANGLE_ENABLE_HLSL return new TranslatorHLSL(type, spec, output); - default: +#else + // This compiler is not supported in this + // configuration. Return NULL per the ShConstructCompiler API. + return NULL; +#endif // ANGLE_ENABLE_HLSL + default: + // Unknown format. Return NULL per the ShConstructCompiler API. return NULL; } } diff --git a/src/3rdparty/angle/src/compiler/translator/Common.h b/src/3rdparty/angle/src/compiler/translator/Common.h index 1e4503e340..ac1aef0f4c 100644 --- a/src/3rdparty/angle/src/compiler/translator/Common.h +++ b/src/3rdparty/angle/src/compiler/translator/Common.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _COMMON_INCLUDED_ -#define _COMMON_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_COMMON_H_ +#define COMPILER_TRANSLATOR_COMMON_H_ #include #include @@ -89,4 +89,4 @@ inline TString str(T i) return buffer; } -#endif // _COMMON_INCLUDED_ +#endif // COMPILER_TRANSLATOR_COMMON_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp index 5c62a64d10..534861ca70 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp @@ -4,7 +4,6 @@ // 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" @@ -126,7 +125,8 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) maxCallStackDepth(0), fragmentPrecisionHigh(false), clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), - builtInFunctionEmulator(type) + builtInFunctionEmulator(), + mSourcePath(NULL) { } @@ -159,33 +159,41 @@ bool TCompiler::Init(const ShBuiltInResources& resources) return true; } -bool TCompiler::compile(const char* const shaderStrings[], - size_t numStrings, - int compileOptions) +TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[], + size_t numStrings, int compileOptions) +{ + return compileTreeImpl(shaderStrings, numStrings, compileOptions); +} + +TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[], + size_t numStrings, int compileOptions) { - TScopedPoolAllocator scopedAlloc(&allocator); clearResults(); - if (numStrings == 0) - return true; + ASSERT(numStrings > 0); + ASSERT(GetGlobalPoolAllocator()); + + // Reset the extension behavior for each compilation unit. + ResetExtensionBehavior(extensionBehavior); // If compiling for WebGL, validate loop and indexing as well. if (IsWebGLBasedSpec(shaderSpec)) compileOptions |= SH_VALIDATE_LOOP_INDEXING; // First string is path of source file if flag is set. The actual source follows. - const char* sourcePath = NULL; size_t firstSource = 0; if (compileOptions & SH_SOURCE_PATH) { - sourcePath = shaderStrings[0]; + mSourcePath = shaderStrings[0]; ++firstSource; } + bool debugShaderPrecision = getResources().WEBGL_debug_shader_precision == 1; TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, compileOptions, true, - sourcePath, infoSink); + infoSink, debugShaderPrecision); + parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh; SetGlobalParseContext(&parseContext); @@ -206,6 +214,8 @@ bool TCompiler::compile(const char* const shaderStrings[], success = false; } + TIntermNode *root = NULL; + if (success) { mPragma = parseContext.pragma(); @@ -214,7 +224,7 @@ bool TCompiler::compile(const char* const shaderStrings[], symbolTable.setGlobalInvariant(); } - TIntermNode* root = parseContext.treeRoot; + root = parseContext.treeRoot; success = intermediate.postProcess(root); // Disallow expressions deemed too complex. @@ -255,8 +265,11 @@ bool TCompiler::compile(const char* const shaderStrings[], } // Built-in function emulation needs to happen after validateLimitations pass. - if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) + if (success) + { + initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions); builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); + } // Clamping uniform array bounds needs to happen after validateLimitations pass. if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) @@ -301,18 +314,37 @@ bool TCompiler::compile(const char* const shaderStrings[], RegenerateStructNames gen(symbolTable, shaderVersion); root->traverse(&gen); } - - if (success && (compileOptions & SH_INTERMEDIATE_TREE)) - intermediate.outputTree(root); - - if (success && (compileOptions & SH_OBJECT_CODE)) - translate(root); } - // Cleanup memory. - intermediate.remove(parseContext.treeRoot); SetGlobalParseContext(NULL); - return success; + if (success) + return root; + + return NULL; +} + +bool TCompiler::compile(const char* const shaderStrings[], + size_t numStrings, int compileOptions) +{ + if (numStrings == 0) + return true; + + TScopedPoolAllocator scopedAlloc(&allocator); + TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions); + + if (root) + { + if (compileOptions & SH_INTERMEDIATE_TREE) + TIntermediate::outputTree(root, infoSink.info); + + if (compileOptions & SH_OBJECT_CODE) + translate(root, compileOptions); + + // The IntermNode tree doesn't need to be deleted here, since the + // memory will be freed in a big chunk by the PoolAllocator. + return true; + } + return false; } bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) @@ -390,11 +422,15 @@ void TCompiler::setResourceString() << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth << ":EXT_frag_depth:" << compileResources.EXT_frag_depth << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod + << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch + << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch + << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset - << ":NV_draw_buffers:" << compileResources.NV_draw_buffers; + << ":NV_draw_buffers:" << compileResources.NV_draw_buffers + << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision; builtInResourcesString = strstream.str(); } @@ -416,27 +452,29 @@ void TCompiler::clearResults() builtInFunctionEmulator.Cleanup(); nameMap.clear(); + + mSourcePath = NULL; } -bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth) +bool TCompiler::detectCallDepth(TIntermNode* inputRoot, TInfoSink& inputInfoSink, bool limitCallStackDepth) { - DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth); - root->traverse(&detect); + DetectCallDepth detect(inputInfoSink, limitCallStackDepth, maxCallStackDepth); + inputRoot->traverse(&detect); switch (detect.detectCallDepth()) { case DetectCallDepth::kErrorNone: return true; case DetectCallDepth::kErrorMissingMain: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Missing main()"; + inputInfoSink.info.prefix(EPrefixError); + inputInfoSink.info << "Missing main()"; return false; case DetectCallDepth::kErrorRecursion: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Function recursion detected"; + inputInfoSink.info.prefix(EPrefixError); + inputInfoSink.info << "Function recursion detected"; return false; case DetectCallDepth::kErrorMaxDepthExceeded: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Function call stack too deep"; + inputInfoSink.info.prefix(EPrefixError); + inputInfoSink.info << "Function call stack too deep"; return false; default: UNREACHABLE(); @@ -594,6 +632,11 @@ const TExtensionBehavior& TCompiler::getExtensionBehavior() const return extensionBehavior; } +const char *TCompiler::getSourcePath() const +{ + return mSourcePath; +} + const ShBuiltInResources& TCompiler::getResources() const { return compileResources; diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.h b/src/3rdparty/angle/src/compiler/translator/Compiler.h index b6c9d13ed0..bcdb0d4c9d 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.h +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _SHHANDLE_INCLUDED_ -#define _SHHANDLE_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_COMPILER_H_ +#define COMPILER_TRANSLATOR_COMPILER_H_ // // Machine independent part of the compiler private objects @@ -25,7 +25,9 @@ class TCompiler; class TDependencyGraph; +#ifdef ANGLE_ENABLE_HLSL class TranslatorHLSL; +#endif // ANGLE_ENABLE_HLSL // // Helper function to identify specs that are based on the WebGL spec, @@ -41,7 +43,9 @@ public: TShHandleBase(); virtual ~TShHandleBase(); virtual TCompiler* getAsCompiler() { return 0; } +#ifdef ANGLE_ENABLE_HLSL virtual TranslatorHLSL* getAsTranslatorHLSL() { return 0; } +#endif // ANGLE_ENABLE_HLSL protected: // Memory allocator. Allocates and tracks memory required by the compiler. @@ -61,9 +65,15 @@ class TCompiler : public TShHandleBase virtual TCompiler* getAsCompiler() { return this; } bool Init(const ShBuiltInResources& resources); + + // compileTreeForTesting should be used only when tests require access to + // the AST. Users of this function need to manually manage the global pool + // allocator. Returns NULL whenever there are compilation errors. + TIntermNode *compileTreeForTesting(const char* const shaderStrings[], + size_t numStrings, int compileOptions); + bool compile(const char* const shaderStrings[], - size_t numStrings, - int compileOptions); + size_t numStrings, int compileOptions); // Get results of the last compilation. int getShaderVersion() const { return shaderVersion; } @@ -104,8 +114,10 @@ class TCompiler : public TShHandleBase bool validateLimitations(TIntermNode* root); // Collect info for all attribs, uniforms, varyings. void collectVariables(TIntermNode* root); + // Add emulated functions to the built-in function emulator. + virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) {}; // Translate to object code. - virtual void translate(TIntermNode* root) = 0; + virtual void translate(TIntermNode *root, int compileOptions) = 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(); @@ -130,6 +142,7 @@ class TCompiler : public TShHandleBase bool limitExpressionComplexity(TIntermNode* root); // Get built-in extensions with default behavior. const TExtensionBehavior& getExtensionBehavior() const; + const char *getSourcePath() const; const TPragma& getPragma() const { return mPragma; } void writePragma(); @@ -145,6 +158,9 @@ class TCompiler : public TShHandleBase std::vector interfaceBlocks; private: + TIntermNode *compileTreeImpl(const char* const shaderStrings[], + size_t numStrings, int compileOptions); + sh::GLenum shaderType; ShShaderSpec shaderSpec; ShShaderOutput outputType; @@ -170,6 +186,7 @@ class TCompiler : public TShHandleBase // Results of compilation. int shaderVersion; TInfoSink infoSink; // Output sink. + const char *mSourcePath; // Path of source file or NULL // name hashing. ShHashFunction64 hashFunction; @@ -191,4 +208,4 @@ TCompiler* ConstructCompiler( sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); void DeleteCompiler(TCompiler*); -#endif // _SHHANDLE_INCLUDED_ +#endif // COMPILER_TRANSLATOR_COMPILER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h index 5e86c64805..31ff2ccfa7 100644 --- a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h +++ b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _CONSTANT_UNION_INCLUDED_ -#define _CONSTANT_UNION_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_CONSTANTUNION_H_ +#define COMPILER_TRANSLATOR_CONSTANTUNION_H_ #include @@ -254,7 +254,10 @@ public: ConstantUnion operator<<(const ConstantUnion& constant) const { ConstantUnion returnValue; - assert(type == constant.type); + // The signedness of the second parameter might be different, but we + // don't care, since the result is undefined if the second parameter is + // negative, and aliasing should not be a problem with unions. + assert(constant.type == EbtInt || constant.type == EbtUInt); switch (type) { case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; case EbtUInt: returnValue.setUConst(uConst << constant.uConst); break; @@ -267,7 +270,7 @@ public: ConstantUnion operator&(const ConstantUnion& constant) const { ConstantUnion returnValue; - assert(type == constant.type); + assert(constant.type == EbtInt || constant.type == EbtUInt); switch (type) { case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; case EbtUInt: returnValue.setUConst(uConst & constant.uConst); break; @@ -340,4 +343,4 @@ private: TBasicType type; }; -#endif // _CONSTANT_UNION_INCLUDED_ +#endif // COMPILER_TRANSLATOR_CONSTANTUNION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp index bfc1d5852f..0dc5d22709 100644 --- a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp +++ b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp @@ -33,7 +33,7 @@ int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDe ASSERT(visit == PreVisit); ASSERT(detectCallDepth); - int maxDepth = depth; + int retMaxDepth = depth; visit = InVisit; for (size_t i = 0; i < callees.size(); ++i) { switch (callees[i]->visit) { @@ -52,7 +52,7 @@ int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDe detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName(); return callDepth; } - maxDepth = std::max(callDepth, maxDepth); + retMaxDepth = std::max(callDepth, retMaxDepth); break; } default: @@ -61,7 +61,7 @@ int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDe } } visit = PostVisit; - return maxDepth; + return retMaxDepth; } void DetectCallDepth::FunctionNode::reset() diff --git a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h index 86810650dc..8dd1391e67 100644 --- a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h +++ b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_DETECT_RECURSION_H_ -#define COMPILER_DETECT_RECURSION_H_ +#ifndef COMPILER_TRANSLATOR_DETECTCALLDEPTH_H_ +#define COMPILER_TRANSLATOR_DETECTCALLDEPTH_H_ #include #include "compiler/translator/IntermNode.h" @@ -75,4 +75,4 @@ private: void operator=(const DetectCallDepth&); }; -#endif // COMPILER_DETECT_RECURSION_H_ +#endif // COMPILER_TRANSLATOR_DETECTCALLDEPTH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h index 67e37be398..623be13533 100644 --- a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h +++ b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h @@ -8,8 +8,8 @@ // gradients of functions with discontinuities. // -#ifndef COMPILER_DETECTDISCONTINUITY_H_ -#define COMPILER_DETECTDISCONTINUITY_H_ +#ifndef COMPILER_TRANSLATOR_DETECTDISCONTINUITY_H_ +#define COMPILER_TRANSLATOR_DETECTDISCONTINUITY_H_ #include "compiler/translator/IntermNode.h" @@ -68,4 +68,4 @@ bool containsGradientOperation(TIntermNode *node); } -#endif // COMPILER_DETECTDISCONTINUITY_H_ +#endif // COMPILER_TRANSLATOR_DETECTDISCONTINUITY_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h index 664da7803b..078bc97772 100644 --- a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h +++ b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h @@ -4,14 +4,15 @@ // found in the LICENSE file. // -#ifndef COMPILER_DIAGNOSTICS_H_ -#define COMPILER_DIAGNOSTICS_H_ +#ifndef COMPILER_TRANSLATOR_DIAGNOSTICS_H_ +#define COMPILER_TRANSLATOR_DIAGNOSTICS_H_ +#include "common/angleutils.h" #include "compiler/preprocessor/DiagnosticsBase.h" class TInfoSink; -class TDiagnostics : public pp::Diagnostics +class TDiagnostics : public pp::Diagnostics, angle::NonCopyable { public: TDiagnostics(TInfoSink& infoSink); @@ -41,4 +42,4 @@ class TDiagnostics : public pp::Diagnostics int mNumWarnings; }; -#endif // COMPILER_DIAGNOSTICS_H_ +#endif // COMPILER_TRANSLATOR_DIAGNOSTICS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp index f67a03aa93..936c00a56c 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp @@ -27,10 +27,12 @@ static TBehavior getBehavior(const std::string& str) TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior, TDiagnostics& diagnostics, - int& shaderVersion) + int& shaderVersion, + bool debugShaderPrecisionSupported) : mExtensionBehavior(extBehavior), mDiagnostics(diagnostics), - mShaderVersion(shaderVersion) + mShaderVersion(shaderVersion), + mDebugShaderPrecisionSupported(debugShaderPrecisionSupported) { } @@ -65,6 +67,7 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, { const char kOptimize[] = "optimize"; const char kDebug[] = "debug"; + const char kDebugShaderPrecision[] = "webgl_debug_shader_precision"; const char kOn[] = "on"; const char kOff[] = "off"; @@ -81,6 +84,12 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, else if (value == kOff) mPragma.debug = false; else invalidValue = true; } + else if (name == kDebugShaderPrecision && mDebugShaderPrecisionSupported) + { + if (value == kOn) mPragma.debugShaderPrecision = true; + else if (value == kOff) mPragma.debugShaderPrecision = false; + else invalidValue = true; + } else { mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name); diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h index 0433c3bf89..2a81ee5707 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h @@ -4,21 +4,23 @@ // found in the LICENSE file. // -#ifndef COMPILER_DIRECTIVE_HANDLER_H_ -#define COMPILER_DIRECTIVE_HANDLER_H_ +#ifndef COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ +#define COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ +#include "common/angleutils.h" #include "compiler/translator/ExtensionBehavior.h" #include "compiler/translator/Pragma.h" #include "compiler/preprocessor/DirectiveHandlerBase.h" class TDiagnostics; -class TDirectiveHandler : public pp::DirectiveHandler +class TDirectiveHandler : public pp::DirectiveHandler, angle::NonCopyable { public: TDirectiveHandler(TExtensionBehavior& extBehavior, TDiagnostics& diagnostics, - int& shaderVersion); + int& shaderVersion, + bool debugShaderPrecisionSupported); virtual ~TDirectiveHandler(); const TPragma& pragma() const { return mPragma; } @@ -44,6 +46,7 @@ class TDirectiveHandler : public pp::DirectiveHandler TExtensionBehavior& mExtensionBehavior; TDiagnostics& mDiagnostics; int& mShaderVersion; + bool mDebugShaderPrecisionSupported; }; -#endif // COMPILER_DIRECTIVE_HANDLER_H_ +#endif // COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp new file mode 100644 index 0000000000..697e042954 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp @@ -0,0 +1,528 @@ +// +// 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/EmulatePrecision.h" + +namespace +{ + +static void writeVectorPrecisionEmulationHelpers( + TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size) +{ + std::stringstream vecTypeStrStr; + if (outputLanguage == SH_ESSL_OUTPUT) + vecTypeStrStr << "highp "; + vecTypeStrStr << "vec" << size; + std::string vecType = vecTypeStrStr.str(); + + sink << + vecType << " angle_frm(in " << vecType << " v) {\n" + " v = clamp(v, -65504.0, 65504.0);\n" + " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" + " bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n" + " v = v * exp2(-exponent);\n" + " v = sign(v) * floor(abs(v));\n" + " return v * exp2(exponent) * vec" << size << "(isNonZero);\n" + "}\n"; + + sink << + vecType << " angle_frl(in " << vecType << " v) {\n" + " v = clamp(v, -2.0, 2.0);\n" + " v = v * 256.0;\n" + " v = sign(v) * floor(abs(v));\n" + " return v * 0.00390625;\n" + "}\n"; +} + +static void writeMatrixPrecisionEmulationHelper( + TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size, const char *functionName) +{ + std::stringstream matTypeStrStr; + if (outputLanguage == SH_ESSL_OUTPUT) + matTypeStrStr << "highp "; + matTypeStrStr << "mat" << size; + std::string matType = matTypeStrStr.str(); + + sink << matType << " " << functionName << "(in " << matType << " m) {\n" + " " << matType << " rounded;\n"; + + for (unsigned int i = 0; i < size; ++i) + { + sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; + } + + sink << " return rounded;\n" + "}\n"; +} + +static void writeCommonPrecisionEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage) +{ + // Write the angle_frm functions that round floating point numbers to + // half precision, and angle_frl functions that round them to minimum lowp + // precision. + + // Unoptimized version of angle_frm for single floats: + // + // int webgl_maxNormalExponent(in int exponentBits) { + // int possibleExponents = int(exp2(float(exponentBits))); + // int exponentBias = possibleExponents / 2 - 1; + // int allExponentBitsOne = possibleExponents - 1; + // return (allExponentBitsOne - 1) - exponentBias; + // } + // + // float angle_frm(in float x) { + // int mantissaBits = 10; + // int exponentBits = 5; + // float possibleMantissas = exp2(float(mantissaBits)); + // float mantissaMax = 2.0 - 1.0 / possibleMantissas; + // int maxNE = webgl_maxNormalExponent(exponentBits); + // float max = exp2(float(maxNE)) * mantissaMax; + // if (x > max) { + // return max; + // } + // if (x < -max) { + // return -max; + // } + // float exponent = floor(log2(abs(x))); + // if (abs(x) == 0.0 || exponent < -float(maxNE)) { + // return 0.0 * sign(x) + // } + // x = x * exp2(-(exponent - float(mantissaBits))); + // x = sign(x) * floor(abs(x)); + // return x * exp2(exponent - float(mantissaBits)); + // } + + // All numbers with a magnitude less than 2^-15 are subnormal, and are + // flushed to zero. + + // Note the constant numbers below: + // a) 65504 is the maximum possible mantissa (1.1111111111 in binary) times + // 2^15, the maximum normal exponent. + // b) 10.0 is the number of mantissa bits. + // c) -25.0 is the minimum normal half-float exponent -15.0 minus the number + // of mantissa bits. + // d) + 1e-30 is to make sure the argument of log2() won't be zero. It can + // only affect the result of log2 on x where abs(x) < 1e-22. Since these + // numbers will be flushed to zero either way (2^-15 is the smallest + // normal positive number), this does not introduce any error. + + std::string floatType = "float"; + if (outputLanguage == SH_ESSL_OUTPUT) + floatType = "highp float"; + + sink << + floatType << " angle_frm(in " << floatType << " x) {\n" + " x = clamp(x, -65504.0, 65504.0);\n" + " " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n" + " bool isNonZero = (exponent >= -25.0);\n" + " x = x * exp2(-exponent);\n" + " x = sign(x) * floor(abs(x));\n" + " return x * exp2(exponent) * float(isNonZero);\n" + "}\n"; + + sink << + floatType << " angle_frl(in " << floatType << " x) {\n" + " x = clamp(x, -2.0, 2.0);\n" + " x = x * 256.0;\n" + " x = sign(x) * floor(abs(x));\n" + " return x * 0.00390625;\n" + "}\n"; + + writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 2); + writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 3); + writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 4); + for (unsigned int size = 2; size <= 4; ++size) + { + writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frm"); + writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frl"); + } +} + +static void writeCompoundAssignmentPrecisionEmulation( + TInfoSinkBase& sink, ShShaderOutput outputLanguage, + const char *lType, const char *rType, const char *opStr, const char *opNameStr) +{ + std::string lTypeStr = lType; + std::string rTypeStr = rType; + if (outputLanguage == SH_ESSL_OUTPUT) + { + std::stringstream lTypeStrStr; + lTypeStrStr << "highp " << lType; + lTypeStr = lTypeStrStr.str(); + std::stringstream rTypeStrStr; + rTypeStrStr << "highp " << rType; + rTypeStr = rTypeStrStr.str(); + } + + // Note that y should be passed through angle_frm at the function call site, + // but x can't be passed through angle_frm there since it is an inout parameter. + // So only pass x and the result through angle_frm here. + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frm(angle_frm(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frl(angle_frm(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; +} + +const char *getFloatTypeStr(const TType& type) +{ + switch (type.getNominalSize()) + { + case 1: + return "float"; + case 2: + return type.getSecondarySize() > 1 ? "mat2" : "vec2"; + case 3: + return type.getSecondarySize() > 1 ? "mat3" : "vec3"; + case 4: + return type.getSecondarySize() > 1 ? "mat4" : "vec4"; + default: + UNREACHABLE(); + return NULL; + } +} + +bool canRoundFloat(const TType &type) +{ + return type.getBasicType() == EbtFloat && !type.isNonSquareMatrix() && !type.isArray() && + (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium); +} + +TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child) +{ + TIntermAggregate *callNode = new TIntermAggregate(); + callNode->setOp(EOpInternalFunctionCall); + callNode->setName(name); + callNode->getSequence()->push_back(child); + return callNode; +} + +TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild) +{ + TString roundFunctionName; + if (roundedChild->getPrecision() == EbpMedium) + roundFunctionName = "angle_frm"; + else + roundFunctionName = "angle_frl"; + return createInternalFunctionCallNode(roundFunctionName, roundedChild); +} + +TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left, TIntermTyped *right, const char *opNameStr) +{ + std::stringstream strstr; + if (left->getPrecision() == EbpMedium) + strstr << "angle_compound_" << opNameStr << "_frm"; + else + strstr << "angle_compound_" << opNameStr << "_frl"; + TString functionName = strstr.str().c_str(); + TIntermAggregate *callNode = createInternalFunctionCallNode(functionName, left); + callNode->getSequence()->push_back(right); + return callNode; +} + +bool parentUsesResult(TIntermNode* parent, TIntermNode* node) +{ + if (!parent) + { + return false; + } + + TIntermAggregate *aggParent = parent->getAsAggregate(); + // If the parent's op is EOpSequence, the result is not assigned anywhere, + // so rounding it is not needed. In particular, this can avoid a lot of + // unnecessary rounding of unused return values of assignment. + if (aggParent && aggParent->getOp() == EOpSequence) + { + return false; + } + if (aggParent && aggParent->getOp() == EOpComma && (aggParent->getSequence()->back() != node)) + { + return false; + } + return true; +} + +} // namespace anonymous + +EmulatePrecision::EmulatePrecision() + : TIntermTraverser(true, true, true), + mDeclaringVariables(false), + mInLValue(false), + mInFunctionCallOutParameter(false) +{} + +void EmulatePrecision::visitSymbol(TIntermSymbol *node) +{ + if (canRoundFloat(node->getType()) && + !mDeclaringVariables && !mInLValue && !mInFunctionCallOutParameter) + { + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + } +} + + +bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) +{ + bool visitChildren = true; + + if (node->isAssignment()) + { + if (visit == PreVisit) + mInLValue = true; + else if (visit == InVisit) + mInLValue = false; + } + + TOperator op = node->getOp(); + + // RHS of initialize is not being declared. + if (op == EOpInitialize && visit == InVisit) + mDeclaringVariables = false; + + if ((op == EOpIndexDirectStruct || op == EOpVectorSwizzle) && visit == InVisit) + visitChildren = false; + + if (visit != PreVisit) + return visitChildren; + + const TType& type = node->getType(); + bool roundFloat = canRoundFloat(type); + + if (roundFloat) { + switch (op) { + // Math operators that can result in a float may need to apply rounding to the return + // value. Note that in the case of assignment, the rounding is applied to its return + // value here, not the value being assigned. + case EOpAssign: + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + { + TIntermNode *parent = getParentNode(); + if (!parentUsesResult(parent, node)) + { + break; + } + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + break; + } + + // Compound assignment cases need to replace the operator with a function call. + case EOpAddAssign: + { + mEmulateCompoundAdd.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "add"); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); + break; + } + case EOpSubAssign: + { + mEmulateCompoundSub.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "sub"); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); + break; + } + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + { + mEmulateCompoundMul.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "mul"); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); + break; + } + case EOpDivAssign: + { + mEmulateCompoundDiv.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "div"); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); + break; + } + default: + // The rest of the binary operations should not need precision emulation. + break; + } + } + return visitChildren; +} + +bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node) +{ + bool visitChildren = true; + switch (node->getOp()) + { + case EOpSequence: + case EOpConstructStruct: + // No special handling + break; + case EOpFunction: + if (visit == PreVisit) + { + const TIntermSequence &sequence = *(node->getSequence()); + TIntermSequence::const_iterator seqIter = sequence.begin(); + TIntermAggregate *params = (*seqIter)->getAsAggregate(); + ASSERT(params != NULL); + ASSERT(params->getOp() == EOpParameters); + mFunctionMap[node->getName()] = params->getSequence(); + } + break; + case EOpPrototype: + if (visit == PreVisit) + mFunctionMap[node->getName()] = node->getSequence(); + visitChildren = false; + break; + case EOpParameters: + visitChildren = false; + break; + case EOpInvariantDeclaration: + visitChildren = false; + break; + case EOpDeclaration: + // Variable declaration. + if (visit == PreVisit) + { + mDeclaringVariables = true; + } + else if (visit == InVisit) + { + mDeclaringVariables = true; + } + else + { + mDeclaringVariables = false; + } + break; + case EOpFunctionCall: + { + // Function call. + bool inFunctionMap = (mFunctionMap.find(node->getName()) != mFunctionMap.end()); + if (visit == PreVisit) + { + // User-defined function return values are not rounded, this relies on that + // calculations producing the value were rounded. + TIntermNode *parent = getParentNode(); + if (canRoundFloat(node->getType()) && !inFunctionMap && parentUsesResult(parent, node)) + { + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + } + + if (inFunctionMap) + { + mSeqIterStack.push_back(mFunctionMap[node->getName()]->begin()); + if (mSeqIterStack.back() != mFunctionMap[node->getName()]->end()) + { + TQualifier qualifier = (*mSeqIterStack.back())->getAsTyped()->getQualifier(); + mInFunctionCallOutParameter = (qualifier == EvqOut || qualifier == EvqInOut); + } + } + else + { + // The function is not user-defined - it is likely built-in texture function. + // Assume that those do not have out parameters. + mInFunctionCallOutParameter = false; + } + } + else if (visit == InVisit) + { + if (inFunctionMap) + { + ++mSeqIterStack.back(); + TQualifier qualifier = (*mSeqIterStack.back())->getAsTyped()->getQualifier(); + mInFunctionCallOutParameter = (qualifier == EvqOut || qualifier == EvqInOut); + } + } + else + { + if (inFunctionMap) + { + mSeqIterStack.pop_back(); + mInFunctionCallOutParameter = false; + } + } + break; + } + default: + TIntermNode *parent = getParentNode(); + if (canRoundFloat(node->getType()) && visit == PreVisit && parentUsesResult(parent, node)) + { + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + } + break; + } + return visitChildren; +} + +bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node) +{ + switch (node->getOp()) + { + case EOpNegative: + case EOpVectorLogicalNot: + case EOpLogicalNot: + break; + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + if (visit == PreVisit) + mInLValue = true; + else if (visit == PostVisit) + mInLValue = false; + break; + default: + if (canRoundFloat(node->getType()) && visit == PreVisit) + { + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + } + break; + } + + return true; +} + +void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage) +{ + // Other languages not yet supported + ASSERT(outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT || + outputLanguage == SH_GLSL_CORE_OUTPUT || + outputLanguage == SH_ESSL_OUTPUT); + writeCommonPrecisionEmulationHelpers(sink, outputLanguage); + + EmulationSet::const_iterator it; + for (it = mEmulateCompoundAdd.begin(); it != mEmulateCompoundAdd.end(); it++) + writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "+", "add"); + for (it = mEmulateCompoundSub.begin(); it != mEmulateCompoundSub.end(); it++) + writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "-", "sub"); + for (it = mEmulateCompoundDiv.begin(); it != mEmulateCompoundDiv.end(); it++) + writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "/", "div"); + for (it = mEmulateCompoundMul.begin(); it != mEmulateCompoundMul.end(); it++) + writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "*", "mul"); +} + diff --git a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h new file mode 100644 index 0000000000..f1f560aa85 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h @@ -0,0 +1,74 @@ +// +// 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_EMULATE_PRECISION_H_ +#define COMPILER_TRANSLATOR_EMULATE_PRECISION_H_ + +#include "common/angleutils.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/IntermNode.h" +#include "GLSLANG/ShaderLang.h" + +// This class gathers all compound assignments from the AST and can then write +// the functions required for their precision emulation. This way there is no +// need to write a huge number of variations of the emulated compound assignment +// to every translated shader with emulation enabled. + +class EmulatePrecision : public TIntermTraverser +{ + public: + EmulatePrecision(); + + virtual void visitSymbol(TIntermSymbol *node); + virtual bool visitBinary(Visit visit, TIntermBinary *node); + virtual bool visitUnary(Visit visit, TIntermUnary *node); + virtual bool visitAggregate(Visit visit, TIntermAggregate *node); + + void writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage); + + private: + struct TypePair + { + TypePair(const char *l, const char *r) + : lType(l), rType(r) { } + + const char *lType; + const char *rType; + }; + + struct TypePairComparator + { + bool operator() (const TypePair& l, const TypePair& r) const + { + if (l.lType == r.lType) + return l.rType < r.rType; + return l.lType < r.lType; + } + }; + + typedef std::set EmulationSet; + EmulationSet mEmulateCompoundAdd; + EmulationSet mEmulateCompoundSub; + EmulationSet mEmulateCompoundMul; + EmulationSet mEmulateCompoundDiv; + + // Stack of function call parameter iterators + std::vector mSeqIterStack; + + bool mDeclaringVariables; + bool mInLValue; + bool mInFunctionCallOutParameter; + + struct TStringComparator + { + bool operator() (const TString& a, const TString& b) const { return a.compare(b) < 0; } + }; + + // Map from function names to their parameter sequences + std::map mFunctionMap; +}; + +#endif // COMPILER_TRANSLATOR_EMULATE_PRECISION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h index 5c1595fb21..cf4d7fba31 100644 --- a/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h +++ b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _EXTENSION_BEHAVIOR_INCLUDED_ -#define _EXTENSION_BEHAVIOR_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ +#define COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ #include #include @@ -34,4 +34,4 @@ inline const char* getBehaviorString(TBehavior b) // Mapping between extension name and behavior. typedef std::map TExtensionBehavior; -#endif // _EXTENSION_TABLE_INCLUDED_ +#endif // COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h index c93a6f808e..07b9a72c5c 100644 --- a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h +++ b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_FLAGSTD140STRUCTS_H_ -#define COMPILER_FLAGSTD140STRUCTS_H_ +#ifndef COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ +#define COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ #include "compiler/translator/IntermNode.h" @@ -34,4 +34,4 @@ std::vector FlagStd140ValueStructs(TIntermNode *node); } -#endif // COMPILER_FLAGSTD140STRUCTS_H_ +#endif // COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h index a820d2a20d..c8787d55a0 100644 --- a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h +++ b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_FORLOOPUNROLL_H_ -#define COMPILER_FORLOOPUNROLL_H_ +#ifndef COMPILER_TRANSLATOR_FORLOOPUNROLL_H_ +#define COMPILER_TRANSLATOR_FORLOOPUNROLL_H_ #include "compiler/translator/LoopInfo.h" @@ -47,4 +47,4 @@ class ForLoopUnrollMarker : public TIntermTraverser bool mVisitSamplerArrayIndexNodeInsideLoop; }; -#endif +#endif // COMPILER_TRANSLATOR_FORLOOPUNROLL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/HashNames.h b/src/3rdparty/angle/src/compiler/translator/HashNames.h index 26546a3e7b..09c959f9da 100644 --- a/src/3rdparty/angle/src/compiler/translator/HashNames.h +++ b/src/3rdparty/angle/src/compiler/translator/HashNames.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_HASH_NAMES_H_ -#define COMPILER_HASH_NAMES_H_ +#ifndef COMPILER_TRANSLATOR_HASHNAMES_H_ +#define COMPILER_TRANSLATOR_HASHNAMES_H_ #include @@ -15,4 +15,4 @@ typedef std::map NameMap; -#endif // COMPILER_HASH_NAMES_H_ +#endif // COMPILER_TRANSLATOR_HASHNAMES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InfoSink.h b/src/3rdparty/angle/src/compiler/translator/InfoSink.h index 698a8b454b..f47fafa8ee 100644 --- a/src/3rdparty/angle/src/compiler/translator/InfoSink.h +++ b/src/3rdparty/angle/src/compiler/translator/InfoSink.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _INFOSINK_INCLUDED_ -#define _INFOSINK_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_INFOSINK_H_ +#define COMPILER_TRANSLATOR_INFOSINK_H_ #include #include @@ -113,4 +113,4 @@ public: TInfoSinkBase obj; }; -#endif // _INFOSINK_INCLUDED_ +#endif // COMPILER_TRANSLATOR_INFOSINK_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp index 10b21e6d28..9e11405758 100644 --- a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp @@ -21,307 +21,208 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR TType *float2 = new TType(EbtFloat, 2); TType *float3 = new TType(EbtFloat, 3); TType *float4 = new TType(EbtFloat, 4); - TType *int1 = new TType(EbtInt); TType *int2 = new TType(EbtInt, 2); TType *int3 = new TType(EbtInt, 3); - TType *int4 = new TType(EbtInt, 4); + TType *uint1 = new TType(EbtUInt); + TType *bool1 = new TType(EbtBool); + TType *genType = new TType(EbtGenType); + TType *genIType = new TType(EbtGenIType); + TType *genUType = new TType(EbtGenUType); + TType *genBType = new TType(EbtGenBType); // // Angle and Trigonometric Functions. // - 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); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpRadians, genType, "radians", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDegrees, genType, "degrees", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSin, genType, "sin", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCos, genType, "cos", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpTan, genType, "tan", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAsin, genType, "asin", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAcos, genType, "acos", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAtan, genType, "atan", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAtan, genType, "atan", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpSinh, genType, "sinh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpCosh, genType, "cosh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTanh, genType, "tanh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAsinh, genType, "asinh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAcosh, genType, "acosh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAtanh, genType, "atanh", genType); // // Exponential Functions. // - 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); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpPow, genType, "pow", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpExp, genType, "exp", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLog, genType, "log", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpExp2, genType, "exp2", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLog2, genType, "log2", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSqrt, genType, "sqrt", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpInverseSqrt, genType, "inversesqrt", genType); // // Common Functions. // - 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); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAbs, genType, "abs", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAbs, genIType, "abs", genIType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSign, genType, "sign", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpSign, genIType, "sign", genIType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFloor, genType, "floor", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTrunc, genType, "trunc", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRound, genType, "round", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRoundEven, genType, "roundEven", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCeil, genType, "ceil", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFract, genType, "fract", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMod, genType, "mod", genType, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMod, genType, "mod", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMin, genType, "min", genType, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMin, genType, "min", genType, genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genIType, "min", genIType, genIType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genIType, "min", genIType, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genUType, "min", genUType, genUType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genUType, "min", genUType, uint1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMax, genType, "max", genType, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMax, genType, "max", genType, genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genIType, "max", genIType, genIType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genIType, "max", genIType, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genUType, "max", genUType, genUType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genUType, "max", genUType, uint1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpClamp, genType, "clamp", genType, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpClamp, genType, "clamp", genType, genType, genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genIType, "clamp", genIType, int1, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genIType, "clamp", genIType, genIType, genIType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genUType, "clamp", genUType, uint1, uint1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genUType, "clamp", genUType, genUType, genUType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpStep, genType, "step", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpStep, genType, "step", float1, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSmoothStep, genType, "smoothstep", genType, genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSmoothStep, genType, "smoothstep", float1, float1, genType); + + TType *outFloat1 = new TType(EbtFloat); + TType *outFloat2 = new TType(EbtFloat, 2); + TType *outFloat3 = new TType(EbtFloat, 3); + TType *outFloat4 = new TType(EbtFloat, 4); + outFloat1->setQualifier(EvqOut); + outFloat2->setQualifier(EvqOut); + outFloat3->setQualifier(EvqOut); + outFloat4->setQualifier(EvqOut); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float1, "modf", float1, outFloat1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float2, "modf", float2, outFloat2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float3, "modf", float3, outFloat3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float4, "modf", float4, outFloat4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIsNan, genBType, "isnan", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIsInf, genBType, "isinf", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFloatBitsToInt, genIType, "floatBitsToInt", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFloatBitsToUint, genUType, "floatBitsToUint", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIntBitsToFloat, genType, "intBitsToFloat", genIType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUintBitsToFloat, genType, "uintBitsToFloat", genUType); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackSnorm2x16, uint1, "packSnorm2x16", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackUnorm2x16, uint1, "packUnorm2x16", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackHalf2x16, uint1, "packHalf2x16", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackSnorm2x16, float2, "unpackSnorm2x16", uint1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackUnorm2x16, float2, "unpackUnorm2x16", uint1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackHalf2x16, float2, "unpackHalf2x16", uint1); // // Geometric Functions. // - 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); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLength, float1, "length", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDistance, float1, "distance", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDot, float1, "dot", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCross, float3, "cross", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpNormalize, genType, "normalize", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFaceForward, genType, "faceforward", genType, genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpReflect, genType, "reflect", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpRefract, genType, "refract", genType, genType, float1); TType *mat2 = new TType(EbtFloat, 2, 2); TType *mat3 = new TType(EbtFloat, 3, 3); TType *mat4 = new TType(EbtFloat, 4, 4); + TType *mat2x3 = new TType(EbtFloat, 2, 3); + TType *mat3x2 = new TType(EbtFloat, 3, 2); + TType *mat2x4 = new TType(EbtFloat, 2, 4); + TType *mat4x2 = new TType(EbtFloat, 4, 2); + TType *mat3x4 = new TType(EbtFloat, 3, 4); + TType *mat4x3 = new TType(EbtFloat, 4, 3); // // Matrix Functions. // - 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); - TType *bool2 = new TType(EbtBool, 2); - TType *bool3 = new TType(EbtBool, 3); - TType *bool4 = new TType(EbtBool, 4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat2, "matrixCompMult", mat2, mat2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat3, "matrixCompMult", mat3, mat3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat4, "matrixCompMult", mat4, mat4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat2x3, "matrixCompMult", mat2x3, mat2x3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat3x2, "matrixCompMult", mat3x2, mat3x2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat2x4, "matrixCompMult", mat2x4, mat2x4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat4x2, "matrixCompMult", mat4x2, mat4x2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat3x4, "matrixCompMult", mat3x4, mat3x4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat4x3, "matrixCompMult", mat4x3, mat4x3); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2, "outerProduct", float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3, "outerProduct", float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4, "outerProduct", float4, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2x3, "outerProduct", float3, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3x2, "outerProduct", float2, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2x4, "outerProduct", float4, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4x2, "outerProduct", float2, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3x4, "outerProduct", float4, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4x3, "outerProduct", float3, float4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2, "transpose", mat2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3, "transpose", mat3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4, "transpose", mat4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2x3, "transpose", mat3x2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3x2, "transpose", mat2x3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2x4, "transpose", mat4x2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4x2, "transpose", mat2x4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3x4, "transpose", mat4x3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4x3, "transpose", mat3x4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat2, "inverse", mat2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat3, "inverse", mat3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat4, "inverse", mat4); + + TType *vec = new TType(EbtVec); + TType *ivec = new TType(EbtIVec); + TType *uvec = new TType(EbtUVec); + TType *bvec = new TType(EbtBVec); // // Vector relational functions. // - 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(COMMON_BUILTINS, bool2, "lessThan", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThan", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThan", int4, int4); - - 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(COMMON_BUILTINS, bool2, "lessThanEqual", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThanEqual", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThanEqual", int4, int4); - - 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(COMMON_BUILTINS, bool2, "greaterThan", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThan", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThan", int4, int4); - - 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(COMMON_BUILTINS, bool2, "greaterThanEqual", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThanEqual", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThanEqual", int4, int4); - - 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(COMMON_BUILTINS, bool2, "equal", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", int4, int4); - - 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(COMMON_BUILTINS, bool2, "notEqual", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", float4, float4); - - 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(COMMON_BUILTINS, bool2, "notEqual", bool2, bool2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", bool3, bool3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", bool4, bool4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "not", bool2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "not", bool3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "not", bool4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThan, bvec, "lessThan", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThan, bvec, "lessThan", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpLessThan, bvec, "lessThan", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThan, bvec, "greaterThan", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThan, bvec, "greaterThan", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpGreaterThan, bvec, "greaterThan", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpVectorEqual, bvec, "equal", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", bvec, bvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", bvec, bvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAny, bool1, "any", bvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAll, bool1, "all", bvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorLogicalNot, bvec, "not", bvec); TType *sampler2D = new TType(EbtSampler2D); TType *samplerCube = new TType(EbtSamplerCube); @@ -357,10 +258,10 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR /* 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); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DGradEXT", sampler2D, float2, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeGradEXT", samplerCube, float3, float3, float3); } if (type == GL_FRAGMENT_SHADER) @@ -372,32 +273,21 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR if (resources.OES_standard_derivatives) { - 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); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdx, "GL_OES_standard_derivatives", genType, "dFdx", genType); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdy, "GL_OES_standard_derivatives", genType, "dFdy", genType); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpFwidth, "GL_OES_standard_derivatives", genType, "fwidth", genType); } 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); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DLodEXT", sampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeLodEXT", samplerCube, float3, float1); } } - if(type == GL_VERTEX_SHADER) + if (type == GL_VERTEX_SHADER) { symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLod", sampler2D, float2, float1); symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float3, float1); @@ -463,22 +353,11 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerCubeShadow, int1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler2DArrayShadow, int1); - if(type == GL_FRAGMENT_SHADER) + 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, EOpDFdx, genType, "dFdx", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdy, genType, "dFdy", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFwidth, genType, "fwidth", genType); } symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2); @@ -486,7 +365,7 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2); - if(type == GL_FRAGMENT_SHADER) + 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); @@ -499,7 +378,7 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3); symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2); - if(type == GL_FRAGMENT_SHADER) + 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); @@ -600,146 +479,84 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, TSymbolTable &symbolTable) { // - // First, insert some special built-in variables that are not in + // Insert some special built-in variables that are not in // the built-in header files. // - switch(type) { - 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))); + switch (type) + { + 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(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(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(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 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"); - } - - // - // Next, identify which built-ins from the already loaded headers have - // a mapping to an operator. Those that are not identified as such are - // expected to be resolved through a library of functions, versus as - // operations. - // - 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(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 GL_VERTEX_SHADER: - break; - case GL_FRAGMENT_SHADER: - if (resources.OES_standard_derivatives) + if (spec != SH_CSS_SHADERS_SPEC) { - symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdx", EOpDFdx); - symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdy", EOpDFdy); - symbolTable.relateToOperator(ESSL1_BUILTINS, "fwidth", EOpFwidth); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"), + TType(EbtFloat, EbpMedium, EvqFragColor, 4))); + TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true); + fragData.setArraySize(resources.MaxDrawBuffers); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData)); + + if (resources.EXT_frag_depth) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_frag_depth", new TVariable(NewPoolTString("gl_FragDepthEXT"), + TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1))); + } - 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_framebuffer_fetch || resources.NV_shader_framebuffer_fetch) + { + TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true); + lastFragData.setArraySize(resources.MaxDrawBuffers); + + if (resources.EXT_shader_framebuffer_fetch) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); + } + else if (resources.NV_shader_framebuffer_fetch) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragColor"), + TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); + symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); + } + } + else if (resources.ARM_shader_framebuffer_fetch) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragColorARM"), + TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); + } } - if (resources.EXT_shader_texture_lod) + else { - 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"); + 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; - 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"); - } + break; - // Finally add resource-specific variables. - switch(type) { - case GL_FRAGMENT_SHADER: - if (spec != SH_CSS_SHADERS_SPEC) { - // Set up gl_FragData. The array size. - TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true); - fragData.setArraySize(resources.MaxDrawBuffers); - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData)); - } + 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))); + symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_InstanceID"), + TType(EbtInt, EbpHigh, EvqInstanceID, 1))); break; - default: break; + + default: + assert(false && "Language not supported"); } } @@ -758,4 +575,20 @@ void InitExtensionBehavior(const ShBuiltInResources& resources, extBehavior["GL_EXT_frag_depth"] = EBhUndefined; if (resources.EXT_shader_texture_lod) extBehavior["GL_EXT_shader_texture_lod"] = EBhUndefined; + if (resources.EXT_shader_framebuffer_fetch) + extBehavior["GL_EXT_shader_framebuffer_fetch"] = EBhUndefined; + if (resources.NV_shader_framebuffer_fetch) + extBehavior["GL_NV_shader_framebuffer_fetch"] = EBhUndefined; + if (resources.ARM_shader_framebuffer_fetch) + extBehavior["GL_ARM_shader_framebuffer_fetch"] = EBhUndefined; +} + +void ResetExtensionBehavior(TExtensionBehavior &extBehavior) +{ + for (auto ext_iter = extBehavior.begin(); + ext_iter != extBehavior.end(); + ++ext_iter) + { + ext_iter->second = EBhUndefined; + } } diff --git a/src/3rdparty/angle/src/compiler/translator/Initialize.h b/src/3rdparty/angle/src/compiler/translator/Initialize.h index cc1862c90e..c43ce3417a 100644 --- a/src/3rdparty/angle/src/compiler/translator/Initialize.h +++ b/src/3rdparty/angle/src/compiler/translator/Initialize.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _INITIALIZE_INCLUDED_ -#define _INITIALIZE_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_INITIALIZE_H_ +#define COMPILER_TRANSLATOR_INITIALIZE_H_ #include "compiler/translator/Common.h" #include "compiler/translator/Compiler.h" @@ -20,4 +20,10 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, void InitExtensionBehavior(const ShBuiltInResources& resources, TExtensionBehavior& extensionBehavior); -#endif // _INITIALIZE_INCLUDED_ +// Resets the behavior of the extensions listed in |extensionBehavior| to the +// undefined state. These extensions will only be those initially supported in +// the ShBuiltInResources object for this compiler instance. All other +// extensions will remain unsupported. +void ResetExtensionBehavior(TExtensionBehavior &extensionBehavior); + +#endif // COMPILER_TRANSLATOR_INITIALIZE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeDll.h b/src/3rdparty/angle/src/compiler/translator/InitializeDll.h index 43070cc3ff..4c400760f6 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeDll.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeDll.h @@ -3,11 +3,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -#ifndef __INITIALIZEDLL_H -#define __INITIALIZEDLL_H +#ifndef COMPILER_TRANSLATOR_INITIALIZEDLL_H_ +#define COMPILER_TRANSLATOR_INITIALIZEDLL_H_ bool InitProcess(); void DetachProcess(); -#endif // __INITIALIZEDLL_H +#endif // COMPILER_TRANSLATOR_INITIALIZEDLL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h b/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h index 0715941424..8c65cb28da 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h @@ -4,10 +4,10 @@ // found in the LICENSE file. // -#ifndef __INITIALIZE_GLOBALS_INCLUDED_ -#define __INITIALIZE_GLOBALS_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ +#define COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ bool InitializePoolIndex(); void FreePoolIndex(); -#endif // __INITIALIZE_GLOBALS_INCLUDED_ +#endif // COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h index bffbab87d0..fa9b885e80 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_ -#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_ +#define COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_ bool InitializeParseContextIndex(); void FreeParseContextIndex(); @@ -14,4 +14,4 @@ struct TParseContext; extern void SetGlobalParseContext(TParseContext* context); extern TParseContext* GetGlobalParseContext(); -#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#endif // COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h index 59c3ea0a39..4a81266498 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_INITIALIZE_VARIABLES_H_ -#define COMPILER_INITIALIZE_VARIABLES_H_ +#ifndef COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ +#define COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ #include "compiler/translator/IntermNode.h" @@ -47,4 +47,4 @@ class InitializeVariables : public TIntermTraverser bool mCodeInserted; }; -#endif // COMPILER_INITIALIZE_VARIABLES_H_ +#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp index aa0f31d170..266e3c8e3d 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp @@ -157,26 +157,6 @@ bool TIntermLoop::replaceChildNode( 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) { @@ -184,14 +164,6 @@ bool TIntermBranch::replaceChildNode( return false; } -void TIntermBranch::enqueueChildren(std::queue *nodeQueue) const -{ - if (mExpression) - { - nodeQueue->push(mExpression); - } -} - bool TIntermBinary::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { @@ -200,18 +172,6 @@ bool TIntermBinary::replaceChildNode( 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) { @@ -219,14 +179,6 @@ bool TIntermUnary::replaceChildNode( return false; } -void TIntermUnary::enqueueChildren(std::queue *nodeQueue) const -{ - if (mOperand) - { - nodeQueue->push(mOperand); - } -} - bool TIntermAggregate::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { @@ -237,14 +189,6 @@ bool TIntermAggregate::replaceChildNode( return false; } -void TIntermAggregate::enqueueChildren(std::queue *nodeQueue) const -{ - for (size_t childIndex = 0; childIndex < mSequence.size(); childIndex++) - { - nodeQueue->push(mSequence[childIndex]); - } -} - void TIntermAggregate::setPrecisionFromChildren() { if (getBasicType() == EbtBool) @@ -300,20 +244,19 @@ bool TIntermSelection::replaceChildNode( return false; } -void TIntermSelection::enqueueChildren(std::queue *nodeQueue) const +bool TIntermSwitch::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) { - if (mCondition) - { - nodeQueue->push(mCondition); - } - if (mTrueBlock) - { - nodeQueue->push(mTrueBlock); - } - if (mFalseBlock) - { - nodeQueue->push(mFalseBlock); - } + REPLACE_IF_IS(mInit, TIntermTyped, original, replacement); + REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement); + return false; +} + +bool TIntermCase::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); + return false; } // @@ -336,6 +279,12 @@ bool TIntermOperator::isAssignment() const case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: return true; default: return false; @@ -379,65 +328,55 @@ bool TIntermOperator::isConstructor() const // Make sure the type of a unary operator is appropriate for its // combination of operation and operand type. // -// Returns false in nothing makes sense. -// -bool TIntermUnary::promote(TInfoSink &) +void TIntermUnary::promote(const TType *funcReturnType) { switch (mOp) { - case EOpLogicalNot: - if (mOperand->getBasicType() != EbtBool) - return false; + case EOpFloatBitsToInt: + case EOpFloatBitsToUint: + case EOpIntBitsToFloat: + case EOpUintBitsToFloat: + case EOpPackSnorm2x16: + case EOpPackUnorm2x16: + case EOpPackHalf2x16: + case EOpUnpackSnorm2x16: + case EOpUnpackUnorm2x16: + mType.setPrecision(EbpHigh); break; - case EOpNegative: - case EOpPositive: - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - if (mOperand->getBasicType() == EbtBool) - return false; + case EOpUnpackHalf2x16: + mType.setPrecision(EbpMedium); break; - - // operators for built-ins are already type checked against their prototype - case EOpAny: - case EOpAll: - case EOpVectorLogicalNot: - return true; - default: - if (mOperand->getBasicType() != EbtFloat) - return false; + setType(mOperand->getType()); } - setType(mOperand->getType()); - mType.setQualifier(EvqTemporary); + if (funcReturnType != nullptr) + { + if (funcReturnType->getBasicType() == EbtBool) + { + // Bool types should not have precision. + setType(*funcReturnType); + } + else + { + // Precision of the node has been set based on the operand. + setTypePreservePrecision(*funcReturnType); + } + } - return true; + mType.setQualifier(EvqTemporary); } // // Establishes the type of the resultant operation, as well as // makes the operator the correct one for the operands. // -// Returns false if operator can't work on operands. +// For lots of operations it should already be established that the operand +// combination is valid, but returns false if operator can't work on operands. // bool TIntermBinary::promote(TInfoSink &infoSink) { - // This function only handles scalars, vectors, and matrices. - 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 (mLeft->getBasicType() != mRight->getBasicType()) - { - return false; - } + ASSERT(mLeft->isArray() == mRight->isArray()); // // Base assumption: just make the type the same as the left @@ -483,12 +422,9 @@ bool TIntermBinary::promote(TInfoSink &infoSink) // And and Or operate on conditionals // case EOpLogicalAnd: + case EOpLogicalXor: case EOpLogicalOr: - // Both operands must be of type bool. - if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool) - { - return false; - } + ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool); setType(TType(EbtBool, EbpUndefined)); break; @@ -625,12 +561,28 @@ bool TIntermBinary::promote(TInfoSink &infoSink) case EOpAssign: case EOpInitialize: + // No more additional checks are needed. + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); + break; case EOpAdd: case EOpSub: case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: case EOpAddAssign: case EOpSubAssign: case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: if ((mLeft->isMatrix() && mRight->isVector()) || (mLeft->isVector() && mRight->isMatrix())) { @@ -641,13 +593,19 @@ bool TIntermBinary::promote(TInfoSink &infoSink) 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 the nominal sizes of operands do not match: + // One of them must be a scalar. if (!mLeft->isScalar() && !mRight->isScalar()) return false; - // Operator cannot be of type pure assignment. - if (mOp == EOpAssign || mOp == EOpInitialize) + // In the case of compound assignment other than multiply-assign, + // the right side needs to be a scalar. Otherwise a vector/matrix + // would be assigned to a scalar. A scalar can't be shifted by a + // vector either. + if (!mRight->isScalar() && + (isAssignment() || + mOp == EOpBitShiftLeft || + mOp == EOpBitShiftRight)) return false; } @@ -656,6 +614,11 @@ bool TIntermBinary::promote(TInfoSink &infoSink) mLeft->getSecondarySize(), mRight->getSecondarySize()); setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, secondarySize)); + if (mLeft->isArray()) + { + ASSERT(mLeft->getArraySize() == mRight->getArraySize()); + mType.setArraySize(mLeft->getArraySize()); + } } break; @@ -665,11 +628,8 @@ bool TIntermBinary::promote(TInfoSink &infoSink) case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: - if ((mLeft->getNominalSize() != mRight->getNominalSize()) || - (mLeft->getSecondarySize() != mRight->getSecondarySize())) - { - return false; - } + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); setType(TType(EbtBool, EbpUndefined)); break; @@ -793,6 +753,7 @@ TIntermTyped *TIntermConstantUnion::fold( break; case EOpDiv: + case EOpIMod: { tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) @@ -810,6 +771,7 @@ TIntermTyped *TIntermConstantUnion::fold( } else { + ASSERT(op == EOpDiv); tempConstArray[i].setFConst( unionArray[i].getFConst() / rightUnionArray[i].getFConst()); @@ -826,9 +788,19 @@ TIntermTyped *TIntermConstantUnion::fold( } else { - tempConstArray[i].setIConst( - unionArray[i].getIConst() / - rightUnionArray[i].getIConst()); + if (op == EOpDiv) + { + tempConstArray[i].setIConst( + unionArray[i].getIConst() / + rightUnionArray[i].getIConst()); + } + else + { + ASSERT(op == EOpIMod); + tempConstArray[i].setIConst( + unionArray[i].getIConst() % + rightUnionArray[i].getIConst()); + } } break; @@ -842,9 +814,19 @@ TIntermTyped *TIntermConstantUnion::fold( } else { - tempConstArray[i].setUConst( - unionArray[i].getUConst() / - rightUnionArray[i].getUConst()); + if (op == EOpDiv) + { + tempConstArray[i].setUConst( + unionArray[i].getUConst() / + rightUnionArray[i].getUConst()); + } + else + { + ASSERT(op == EOpIMod); + tempConstArray[i].setUConst( + unionArray[i].getUConst() % + rightUnionArray[i].getUConst()); + } } break; @@ -968,6 +950,32 @@ TIntermTyped *TIntermConstantUnion::fold( } break; + case EOpBitwiseAnd: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] & rightUnionArray[i]; + break; + case EOpBitwiseXor: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] ^ rightUnionArray[i]; + break; + case EOpBitwiseOr: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] | rightUnionArray[i]; + break; + case EOpBitShiftLeft: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] << rightUnionArray[i]; + break; + case EOpBitShiftRight: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] >> rightUnionArray[i]; + break; + case EOpLessThan: ASSERT(objectSize == 1); tempConstArray = new ConstantUnion[1]; @@ -1160,6 +1168,23 @@ TIntermTyped *TIntermConstantUnion::fold( } break; + case EOpBitwiseNot: + switch (getType().getBasicType()) + { + case EbtInt: + tempConstArray[i].setIConst(~unionArray[i].getIConst()); + break; + case EbtUInt: + tempConstArray[i].setUConst(~unionArray[i].getUConst()); + break; + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Unary operation not folded into constant"); + return NULL; + } + break; + default: return NULL; } @@ -1181,3 +1206,29 @@ TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunctio TString hashedName = stream.str(); return hashedName; } + +void TIntermTraverser::updateTree() +{ + for (size_t ii = 0; ii < mReplacements.size(); ++ii) + { + const NodeUpdateEntry& entry = mReplacements[ii]; + ASSERT(entry.parent); + bool replaced = entry.parent->replaceChildNode( + entry.original, entry.replacement); + ASSERT(replaced); + + if (!entry.originalBecomesChildOfReplacement) + { + // In AST traversing, a parent is visited before its children. + // After we replace a node, if an immediate child is to + // be replaced, we need to make sure we don't update the replaced + // node; instead, we update the replacement node. + for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj) + { + NodeUpdateEntry& entry2 = mReplacements[jj]; + if (entry2.parent == entry.original) + entry2.parent = entry.replacement; + } + } + } +} diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.h b/src/3rdparty/angle/src/compiler/translator/IntermNode.h index 32c70f4671..9f732cbb00 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermNode.h +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.h @@ -13,182 +13,19 @@ // each node can have it's own type of list of children. // -#ifndef COMPILER_TRANSLATOR_INTERMEDIATE_H_ -#define COMPILER_TRANSLATOR_INTERMEDIATE_H_ +#ifndef COMPILER_TRANSLATOR_INTERMNODE_H_ +#define COMPILER_TRANSLATOR_INTERMNODE_H_ #include "GLSLANG/ShaderLang.h" #include #include +#include "common/angleutils.h" #include "compiler/translator/Common.h" #include "compiler/translator/Types.h" #include "compiler/translator/ConstantUnion.h" - -// -// Operators used by the high-level (parse tree) representation. -// -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, - EOpFunction, // For function definition - EOpParameters, // an aggregate listing the parameters to a function - - EOpDeclaration, - EOpInvariantDeclaration, // Specialized declarations for attributing invariance - EOpPrototype, - - // - // Unary operators - // - - EOpNegative, - EOpPositive, - EOpLogicalNot, - EOpVectorLogicalNot, - - EOpPostIncrement, - EOpPostDecrement, - EOpPreIncrement, - EOpPreDecrement, - - // - // binary operations - // - - EOpAdd, - EOpSub, - EOpMul, - EOpDiv, - EOpEqual, - EOpNotEqual, - EOpVectorEqual, - EOpVectorNotEqual, - EOpLessThan, - EOpGreaterThan, - EOpLessThanEqual, - EOpGreaterThanEqual, - EOpComma, - - EOpVectorTimesScalar, - EOpVectorTimesMatrix, - EOpMatrixTimesVector, - EOpMatrixTimesScalar, - - EOpLogicalOr, - EOpLogicalXor, - EOpLogicalAnd, - - EOpIndexDirect, - EOpIndexIndirect, - EOpIndexDirectStruct, - EOpIndexDirectInterfaceBlock, - - EOpVectorSwizzle, - - // - // Built-in functions potentially mapped to operators - // - - EOpRadians, - EOpDegrees, - EOpSin, - EOpCos, - EOpTan, - EOpAsin, - EOpAcos, - EOpAtan, - - EOpPow, - EOpExp, - EOpLog, - EOpExp2, - EOpLog2, - EOpSqrt, - EOpInverseSqrt, - - EOpAbs, - EOpSign, - EOpFloor, - EOpCeil, - EOpFract, - EOpMod, - EOpMin, - EOpMax, - EOpClamp, - EOpMix, - EOpStep, - EOpSmoothStep, - - EOpLength, - EOpDistance, - EOpDot, - EOpCross, - EOpNormalize, - EOpFaceForward, - EOpReflect, - EOpRefract, - - EOpDFdx, // Fragment only, OES_standard_derivatives extension - EOpDFdy, // Fragment only, OES_standard_derivatives extension - EOpFwidth, // Fragment only, OES_standard_derivatives extension - - EOpMatrixTimesMatrix, - - EOpAny, - EOpAll, - - // - // Branch - // - - EOpKill, // Fragment only - EOpReturn, - EOpBreak, - EOpContinue, - - // - // Constructors - // - - EOpConstructInt, - EOpConstructUInt, - EOpConstructBool, - EOpConstructFloat, - EOpConstructVec2, - EOpConstructVec3, - EOpConstructVec4, - EOpConstructBVec2, - EOpConstructBVec3, - EOpConstructBVec4, - EOpConstructIVec2, - EOpConstructIVec3, - EOpConstructIVec4, - EOpConstructUVec2, - EOpConstructUVec3, - EOpConstructUVec4, - EOpConstructMat2, - EOpConstructMat3, - EOpConstructMat4, - EOpConstructStruct, - - // - // moves - // - - EOpAssign, - EOpInitialize, - EOpAddAssign, - EOpSubAssign, - EOpMulAssign, - EOpVectorTimesMatrixAssign, - EOpVectorTimesScalarAssign, - EOpMatrixTimesScalarAssign, - EOpMatrixTimesMatrixAssign, - EOpDivAssign -}; +#include "compiler/translator/Operator.h" class TIntermTraverser; class TIntermAggregate; @@ -196,10 +33,13 @@ class TIntermBinary; class TIntermUnary; class TIntermConstantUnion; class TIntermSelection; +class TIntermSwitch; +class TIntermCase; class TIntermTyped; class TIntermSymbol; class TIntermLoop; class TInfoSink; +class TInfoSinkBase; class TIntermRaw; // @@ -228,6 +68,8 @@ class TIntermNode virtual TIntermBinary *getAsBinaryNode() { return 0; } virtual TIntermUnary *getAsUnaryNode() { return 0; } virtual TIntermSelection *getAsSelectionNode() { return 0; } + virtual TIntermSwitch *getAsSwitchNode() { return 0; } + virtual TIntermCase *getAsCaseNode() { return 0; } virtual TIntermSymbol *getAsSymbolNode() { return 0; } virtual TIntermLoop *getAsLoopNode() { return 0; } virtual TIntermRaw *getAsRawNode() { return 0; } @@ -237,10 +79,6 @@ class TIntermNode virtual bool replaceChildNode( TIntermNode *original, TIntermNode *replacement) = 0; - // For traversing a tree in no particular order, but using - // heap memory. - virtual void enqueueChildren(std::queue *nodeQueue) const = 0; - protected: TSourceLoc mLine; }; @@ -331,8 +169,6 @@ class TIntermLoop : public TIntermNode void setUnrollFlag(bool flag) { mUnrollFlag = flag; } bool getUnrollFlag() const { return mUnrollFlag; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TLoopType mType; TIntermNode *mInit; // for-loop initialization @@ -360,8 +196,6 @@ class TIntermBranch : public TIntermNode TOperator getFlowOp() { return mFlowOp; } TIntermTyped* getExpression() { return mExpression; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TOperator mFlowOp; TIntermTyped *mExpression; // non-zero except for "return exp;" statements @@ -394,8 +228,6 @@ class TIntermSymbol : public TIntermTyped virtual TIntermSymbol *getAsSymbolNode() { return this; } virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } - virtual void enqueueChildren(std::queue *nodeQueue) const {} - protected: int mId; TString mSymbol; @@ -419,7 +251,6 @@ class TIntermRaw : public TIntermTyped virtual TIntermRaw *getAsRawNode() { return this; } virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } - virtual void enqueueChildren(std::queue *nodeQueue) const {} protected: TString mRawText; @@ -459,8 +290,6 @@ class TIntermConstantUnion : public TIntermTyped TIntermTyped *fold(TOperator, TIntermTyped *, TInfoSink &); - virtual void enqueueChildren(std::queue *nodeQueue) const {} - protected: ConstantUnion *mUnionArrayPointer; }; @@ -519,8 +348,6 @@ class TIntermBinary : public TIntermOperator void setAddIndexClamp() { mAddIndexClamp = true; } bool getAddIndexClamp() { return mAddIndexClamp; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TIntermTyped* mLeft; TIntermTyped* mRight; @@ -556,13 +383,11 @@ class TIntermUnary : public TIntermOperator void setOperand(TIntermTyped *operand) { mOperand = operand; } TIntermTyped *getOperand() { return mOperand; } - bool promote(TInfoSink &); + void promote(const TType *funcReturnType); void setUseEmulatedFunction() { mUseEmulatedFunction = true; } bool getUseEmulatedFunction() { return mUseEmulatedFunction; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TIntermTyped *mOperand; @@ -613,8 +438,6 @@ class TIntermAggregate : public TIntermOperator void setUseEmulatedFunction() { mUseEmulatedFunction = true; } bool getUseEmulatedFunction() { return mUseEmulatedFunction; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - void setPrecisionFromChildren(); void setBuiltInFunctionPrecision(); @@ -634,7 +457,7 @@ class TIntermAggregate : public TIntermOperator }; // -// For if tests. Simplified since there is no switch statement. +// For if tests. // class TIntermSelection : public TIntermTyped { @@ -664,14 +487,64 @@ class TIntermSelection : public TIntermTyped TIntermNode *getFalseBlock() const { return mFalseBlock; } TIntermSelection *getAsSelectionNode() { return this; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TIntermTyped *mCondition; TIntermNode *mTrueBlock; TIntermNode *mFalseBlock; }; +// +// Switch statement. +// +class TIntermSwitch : public TIntermNode +{ + public: + TIntermSwitch(TIntermTyped *init, TIntermAggregate *statementList) + : TIntermNode(), + mInit(init), + mStatementList(statementList) + { + } + + void traverse(TIntermTraverser *it) override; + bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement) override; + + TIntermSwitch *getAsSwitchNode() override { return this; } + + TIntermAggregate *getStatementList() { return mStatementList; } + void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; } + + protected: + TIntermTyped *mInit; + TIntermAggregate *mStatementList; +}; + +// +// Case label. +// +class TIntermCase : public TIntermNode +{ + public: + TIntermCase(TIntermTyped *condition) + : TIntermNode(), + mCondition(condition) + { + } + + void traverse(TIntermTraverser *it) override; + bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement) override; + + TIntermCase *getAsCaseNode() override { return this; } + + bool hasCondition() const { return mCondition != nullptr; } + TIntermTyped *getCondition() const { return mCondition; } + + protected: + TIntermTyped *mCondition; +}; + enum Visit { PreVisit, @@ -687,7 +560,7 @@ enum Visit // When using this, just fill in the methods for nodes you want visited. // Return false from a pre-visit to skip visiting that node's subtree. // -class TIntermTraverser +class TIntermTraverser : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE(); @@ -708,6 +581,8 @@ class TIntermTraverser virtual bool visitBinary(Visit, TIntermBinary *) { return true; } virtual bool visitUnary(Visit, TIntermUnary *) { return true; } virtual bool visitSelection(Visit, TIntermSelection *) { return true; } + virtual bool visitSwitch(Visit, TIntermSwitch *) { return true; } + virtual bool visitCase(Visit, TIntermCase *) { return true; } virtual bool visitAggregate(Visit, TIntermAggregate *) { return true; } virtual bool visitLoop(Visit, TIntermLoop *) { return true; } virtual bool visitBranch(Visit, TIntermBranch *) { return true; } @@ -741,12 +616,38 @@ class TIntermTraverser const bool postVisit; const bool rightToLeft; + // If traversers need to replace nodes, they can add the replacements in + // mReplacements during traversal and the user of the traverser should call + // this function after traversal to perform them. + void updateTree(); + protected: int mDepth; int mMaxDepth; // All the nodes from root to the current node's parent during traversing. TVector mPath; + + struct NodeUpdateEntry + { + NodeUpdateEntry(TIntermNode *_parent, + TIntermNode *_original, + TIntermNode *_replacement, + bool _originalBecomesChildOfReplacement) + : parent(_parent), + original(_original), + replacement(_replacement), + originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) {} + + TIntermNode *parent; + TIntermNode *original; + TIntermNode *replacement; + bool originalBecomesChildOfReplacement; + }; + + // During traversing, save all the changes that need to happen into + // mReplacements, then do them by calling updateTree(). + std::vector mReplacements; }; // @@ -768,10 +669,10 @@ class TMaxDepthTraverser : public TIntermTraverser virtual bool visitLoop(Visit, TIntermLoop *) { return depthCheck(); } virtual bool visitBranch(Visit, TIntermBranch *) { return depthCheck(); } -protected: + protected: bool depthCheck() const { return mMaxDepth < mDepthLimit; } int mDepthLimit; }; -#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_ +#endif // COMPILER_TRANSLATOR_INTERMNODE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp index 72b2033fb3..7a7efb71f5 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp +++ b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp @@ -193,6 +193,60 @@ void TIntermSelection::traverse(TIntermTraverser *it) it->visitSelection(PostVisit, this); } +// +// Traverse a switch node. Same comments in binary node apply here. +// +void TIntermSwitch::traverse(TIntermTraverser *it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitSwitch(PreVisit, this); + + if (visit) + { + it->incrementDepth(this); + if (it->rightToLeft) + { + if (mStatementList) + mStatementList->traverse(it); + if (it->inVisit) + visit = it->visitSwitch(InVisit, this); + if (visit) + mInit->traverse(it); + } + else + { + mInit->traverse(it); + if (it->inVisit) + visit = it->visitSwitch(InVisit, this); + if (visit && mStatementList) + mStatementList->traverse(it); + } + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitSwitch(PostVisit, this); +} + +// +// Traverse a switch node. Same comments in binary node apply here. +// +void TIntermCase::traverse(TIntermTraverser *it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitCase(PreVisit, this); + + if (visit && mCondition) + mCondition->traverse(it); + + if (visit && it->postVisit) + it->visitCase(PostVisit, this); +} + // // Traverse a loop node. Same comments in binary node apply here. // diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp index e558683c55..320056f8ce 100644 --- a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp @@ -13,7 +13,6 @@ #include #include "compiler/translator/Intermediate.h" -#include "compiler/translator/RemoveTree.h" #include "compiler/translator/SymbolTable.h" //////////////////////////////////////////////////////////////////////////// @@ -46,47 +45,6 @@ TIntermSymbol *TIntermediate::addSymbol( TIntermTyped *TIntermediate::addBinaryMath( TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) { - 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; - } - - if (left->getBasicType() != right->getBasicType()) - { - return NULL; - } - // // Need a new node holding things together then. Make // one and promote it to the right type. @@ -169,45 +127,8 @@ TIntermTyped *TIntermediate::addIndex( // Returns the added node. // TIntermTyped *TIntermediate::addUnaryMath( - TOperator op, TIntermNode *childNode, const TSourceLoc &line) + TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType) { - TIntermUnary *node; - TIntermTyped *child = childNode->getAsTyped(); - - if (child == NULL) - { - mInfoSink.info.message(EPrefixInternalError, line, - "Bad type in AddUnaryMath"); - return NULL; - } - - 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: - case EOpPositive: - if (child->getType().getBasicType() == EbtStruct || - child->getType().isArray()) - { - return NULL; - } - default: - break; - } - TIntermConstantUnion *childTempConstant = 0; if (child->getAsConstantUnion()) childTempConstant = child->getAsConstantUnion(); @@ -215,12 +136,10 @@ TIntermTyped *TIntermediate::addUnaryMath( // // Make a new node for the operator. // - node = new TIntermUnary(op); + TIntermUnary *node = new TIntermUnary(op); node->setLine(line); node->setOperand(child); - - if (!node->promote(mInfoSink)) - return 0; + node->promote(funcReturnType); if (childTempConstant) { @@ -423,6 +342,24 @@ TIntermTyped *TIntermediate::addSelection( return node; } +TIntermSwitch *TIntermediate::addSwitch( + TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line) +{ + TIntermSwitch *node = new TIntermSwitch(init, statementList); + node->setLine(line); + + return node; +} + +TIntermCase *TIntermediate::addCase( + TIntermTyped *condition, const TSourceLoc &line) +{ + TIntermCase *node = new TIntermCase(condition); + node->setLine(line); + + return node; +} + // // Constant terminal nodes. Has a union that contains bool, float or int constants // @@ -510,12 +447,3 @@ bool TIntermediate::postProcess(TIntermNode *root) return true; } - -// -// This deletes the tree. -// -void TIntermediate::remove(TIntermNode *root) -{ - if (root) - RemoveAllTreeNodes(root); -} diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.h b/src/3rdparty/angle/src/compiler/translator/Intermediate.h new file mode 100644 index 0000000000..ec73e22834 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/Intermediate.h @@ -0,0 +1,71 @@ +// +// 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_INTERMEDIATE_H_ +#define COMPILER_TRANSLATOR_INTERMEDIATE_H_ + +#include "compiler/translator/IntermNode.h" + +struct TVectorFields +{ + int offsets[4]; + int num; +}; + +// +// Set of helper functions to help parse and build the tree. +// +class TInfoSink; +class TIntermediate +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + 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, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType); + 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 &); + TIntermSwitch *addSwitch( + TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line); + TIntermCase *addCase( + TIntermTyped *condition, const TSourceLoc &line); + 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 *); + + static void outputTree(TIntermNode *, TInfoSinkBase &); + + private: + void operator=(TIntermediate &); // prevent assignments + + TInfoSink & mInfoSink; +}; + +#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/LoopInfo.h b/src/3rdparty/angle/src/compiler/translator/LoopInfo.h index 5f72a6e944..ec73fd0fa5 100644 --- a/src/3rdparty/angle/src/compiler/translator/LoopInfo.h +++ b/src/3rdparty/angle/src/compiler/translator/LoopInfo.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATOR_LOOP_INFO_H_ -#define COMPILER_TRANSLATOR_LOOP_INFO_H_ +#ifndef COMPILER_TRANSLATOR_LOOPINFO_H_ +#define COMPILER_TRANSLATOR_LOOPINFO_H_ #include "compiler/translator/IntermNode.h" @@ -76,5 +76,5 @@ class TLoopStack : public TVector void pop(); }; -#endif // COMPILER_TRANSLATOR_LOOP_INDEX_H_ +#endif // COMPILER_TRANSLATOR_LOOPINFO_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/MMap.h b/src/3rdparty/angle/src/compiler/translator/MMap.h index a308671514..fca843992b 100644 --- a/src/3rdparty/angle/src/compiler/translator/MMap.h +++ b/src/3rdparty/angle/src/compiler/translator/MMap.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _MMAP_INCLUDED_ -#define _MMAP_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_MMAP_H_ +#define COMPILER_TRANSLATOR_MMAP_H_ // // Encapsulate memory mapped files @@ -53,4 +53,4 @@ private: char* fBuff; // the actual data; }; -#endif // _MMAP_INCLUDED_ +#endif // COMPILER_TRANSLATOR_MMAP_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/NodeSearch.h b/src/3rdparty/angle/src/compiler/translator/NodeSearch.h index 60070c9d33..8ffed614c3 100644 --- a/src/3rdparty/angle/src/compiler/translator/NodeSearch.h +++ b/src/3rdparty/angle/src/compiler/translator/NodeSearch.h @@ -6,8 +6,8 @@ // NodeSearch.h: Utilities for searching translator node graphs // -#ifndef TRANSLATOR_NODESEARCH_H_ -#define TRANSLATOR_NODESEARCH_H_ +#ifndef COMPILER_TRANSLATOR_NODESEARCH_H_ +#define COMPILER_TRANSLATOR_NODESEARCH_H_ #include "compiler/translator/IntermNode.h" @@ -77,4 +77,4 @@ class FindSideEffectRewriting : public NodeSearchTraverser"; + case EOpLessThanEqual: return "<="; + case EOpGreaterThanEqual: return ">="; + case EOpComma: return ","; + + // Fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: return "*"; + + case EOpLogicalOr: return "||"; + case EOpLogicalXor: return "^^"; + case EOpLogicalAnd: return "&&"; + + case EOpBitShiftLeft: return "<<"; + case EOpBitShiftRight: return ">>"; + + case EOpBitwiseAnd: return "&"; + case EOpBitwiseXor: return "^"; + case EOpBitwiseOr: return "|"; + + // Fall-through. + case EOpIndexDirect: + case EOpIndexIndirect: return "[]"; + + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: return "."; + + case EOpVectorSwizzle: 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 EOpSinh: return "sinh"; + case EOpCosh: return "cosh"; + case EOpTanh: return "tanh"; + case EOpAsinh: return "asinh"; + case EOpAcosh: return "acosh"; + case EOpAtanh: return "atanh"; + + case EOpPow: return "pow"; + 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 EOpTrunc: return "trunc"; + case EOpRound: return "round"; + case EOpRoundEven: return "roundEven"; + case EOpCeil: return "ceil"; + case EOpFract: return "fract"; + case EOpMod: return "mod"; + case EOpModf: return "modf"; + case EOpMin: return "min"; + case EOpMax: return "max"; + case EOpClamp: return "clamp"; + case EOpMix: return "mix"; + case EOpStep: return "step"; + case EOpSmoothStep: return "smoothstep"; + case EOpIsNan: return "isnan"; + case EOpIsInf: return "isinf"; + + case EOpFloatBitsToInt: return "floatBitsToInt"; + case EOpFloatBitsToUint: return "floatBitsToUint"; + case EOpIntBitsToFloat: return "intBitsToFloat"; + case EOpUintBitsToFloat: return "uintBitsToFloat"; + + case EOpPackSnorm2x16: return "packSnorm2x16"; + case EOpPackUnorm2x16: return "packUnorm2x16"; + case EOpPackHalf2x16: return "packHalf2x16"; + case EOpUnpackSnorm2x16: return "unpackSnorm2x16"; + case EOpUnpackUnorm2x16: return "unpackUnorm2x16"; + case EOpUnpackHalf2x16: return "unpackHalf2x16"; + + case EOpLength: return "length"; + case EOpDistance: return "distance"; + case EOpDot: return "dot"; + case EOpCross: return "cross"; + case EOpNormalize: return "normalize"; + case EOpFaceForward: return "faceforward"; + case EOpReflect: return "reflect"; + case EOpRefract: return "refract"; + + case EOpDFdx: return "dFdx"; + case EOpDFdy: return "dFdy"; + case EOpFwidth: return "fwidth"; + + case EOpMatrixTimesMatrix: return "*"; + + case EOpOuterProduct: return "outerProduct"; + case EOpTranspose: return "transpose"; + case EOpDeterminant: return "determinant"; + case EOpInverse: return "inverse"; + + case EOpAny: return "any"; + case EOpAll: return "all"; + + case EOpKill: return "kill"; + case EOpReturn: return "return"; + case EOpBreak: return "break"; + case EOpContinue: return "continue"; + + case EOpConstructInt: return "int"; + case EOpConstructUInt: return "uint"; + case EOpConstructBool: return "bool"; + case EOpConstructFloat: return "float"; + case EOpConstructVec2: return "vec2"; + case EOpConstructVec3: return "vec3"; + case EOpConstructVec4: return "vec4"; + case EOpConstructBVec2: return "bvec2"; + case EOpConstructBVec3: return "bvec3"; + case EOpConstructBVec4: return "bvec4"; + case EOpConstructIVec2: return "ivec2"; + case EOpConstructIVec3: return "ivec3"; + case EOpConstructIVec4: return "ivec4"; + case EOpConstructUVec2: return "uvec2"; + case EOpConstructUVec3: return "uvec3"; + case EOpConstructUVec4: return "uvec4"; + case EOpConstructMat2: return "mat2"; + case EOpConstructMat3: return "mat3"; + case EOpConstructMat4: return "mat4"; + // Note: EOpConstructStruct can't be handled here + + case EOpAssign: return "="; + case EOpInitialize: return "="; + case EOpAddAssign: return "+="; + case EOpSubAssign: return "-="; + + // Fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: return "*="; + + case EOpDivAssign: return "/="; + case EOpIModAssign: return "%="; + case EOpBitShiftLeftAssign: return "<<="; + case EOpBitShiftRightAssign: return ">>="; + case EOpBitwiseAndAssign: return "&="; + case EOpBitwiseXorAssign: return "^="; + case EOpBitwiseOrAssign: return "|="; + + default: break; + } + return ""; +} + diff --git a/src/3rdparty/angle/src/compiler/translator/Operator.h b/src/3rdparty/angle/src/compiler/translator/Operator.h new file mode 100644 index 0000000000..8290f952fc --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/Operator.h @@ -0,0 +1,226 @@ +// +// Copyright (c) 2002-2015 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_OPERATOR_H_ +#define COMPILER_TRANSLATOR_OPERATOR_H_ + +// +// Operators used by the high-level (parse tree) representation. +// +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, + EOpInternalFunctionCall, // Call to an internal helper function + EOpFunction, // For function definition + EOpParameters, // an aggregate listing the parameters to a function + + EOpDeclaration, + EOpInvariantDeclaration, // Specialized declarations for attributing invariance + EOpPrototype, + + // + // Unary operators + // + + EOpNegative, + EOpPositive, + EOpLogicalNot, + EOpVectorLogicalNot, + EOpBitwiseNot, + + EOpPostIncrement, + EOpPostDecrement, + EOpPreIncrement, + EOpPreDecrement, + + // + // binary operations + // + + EOpAdd, + EOpSub, + EOpMul, + EOpDiv, + EOpIMod, + EOpEqual, + EOpNotEqual, + EOpVectorEqual, + EOpVectorNotEqual, + EOpLessThan, + EOpGreaterThan, + EOpLessThanEqual, + EOpGreaterThanEqual, + EOpComma, + + EOpVectorTimesScalar, + EOpVectorTimesMatrix, + EOpMatrixTimesVector, + EOpMatrixTimesScalar, + + EOpLogicalOr, + EOpLogicalXor, + EOpLogicalAnd, + + EOpBitShiftLeft, + EOpBitShiftRight, + + EOpBitwiseAnd, + EOpBitwiseXor, + EOpBitwiseOr, + + EOpIndexDirect, + EOpIndexIndirect, + EOpIndexDirectStruct, + EOpIndexDirectInterfaceBlock, + + EOpVectorSwizzle, + + // + // Built-in functions potentially mapped to operators + // + + EOpRadians, + EOpDegrees, + EOpSin, + EOpCos, + EOpTan, + EOpAsin, + EOpAcos, + EOpAtan, + + EOpSinh, + EOpCosh, + EOpTanh, + EOpAsinh, + EOpAcosh, + EOpAtanh, + + EOpPow, + EOpExp, + EOpLog, + EOpExp2, + EOpLog2, + EOpSqrt, + EOpInverseSqrt, + + EOpAbs, + EOpSign, + EOpFloor, + EOpTrunc, + EOpRound, + EOpRoundEven, + EOpCeil, + EOpFract, + EOpMod, + EOpModf, + EOpMin, + EOpMax, + EOpClamp, + EOpMix, + EOpStep, + EOpSmoothStep, + EOpIsNan, + EOpIsInf, + + EOpFloatBitsToInt, + EOpFloatBitsToUint, + EOpIntBitsToFloat, + EOpUintBitsToFloat, + + EOpPackSnorm2x16, + EOpPackUnorm2x16, + EOpPackHalf2x16, + EOpUnpackSnorm2x16, + EOpUnpackUnorm2x16, + EOpUnpackHalf2x16, + + EOpLength, + EOpDistance, + EOpDot, + EOpCross, + EOpNormalize, + EOpFaceForward, + EOpReflect, + EOpRefract, + + EOpDFdx, // Fragment only, OES_standard_derivatives extension + EOpDFdy, // Fragment only, OES_standard_derivatives extension + EOpFwidth, // Fragment only, OES_standard_derivatives extension + + EOpMatrixTimesMatrix, + + EOpOuterProduct, + EOpTranspose, + EOpDeterminant, + EOpInverse, + + EOpAny, + EOpAll, + + // + // Branch + // + + EOpKill, // Fragment only + EOpReturn, + EOpBreak, + EOpContinue, + + // + // Constructors + // + + EOpConstructInt, + EOpConstructUInt, + EOpConstructBool, + EOpConstructFloat, + EOpConstructVec2, + EOpConstructVec3, + EOpConstructVec4, + EOpConstructBVec2, + EOpConstructBVec3, + EOpConstructBVec4, + EOpConstructIVec2, + EOpConstructIVec3, + EOpConstructIVec4, + EOpConstructUVec2, + EOpConstructUVec3, + EOpConstructUVec4, + EOpConstructMat2, + EOpConstructMat3, + EOpConstructMat4, + EOpConstructStruct, + + // + // moves + // + + EOpAssign, + EOpInitialize, + EOpAddAssign, + EOpSubAssign, + + EOpMulAssign, + EOpVectorTimesMatrixAssign, + EOpVectorTimesScalarAssign, + EOpMatrixTimesScalarAssign, + EOpMatrixTimesMatrixAssign, + + EOpDivAssign, + EOpIModAssign, + EOpBitShiftLeftAssign, + EOpBitShiftRightAssign, + EOpBitwiseAndAssign, + EOpBitwiseXorAssign, + EOpBitwiseOrAssign +}; + +// Returns the string corresponding to the operator in GLSL +const char* GetOperatorString(TOperator op); + +#endif // COMPILER_TRANSLATOR_OPERATOR_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp index 65635af1ff..77e0a8fb37 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp @@ -6,13 +6,21 @@ #include "compiler/translator/OutputESSL.h" -TOutputESSL::TOutputESSL(TInfoSinkBase& objSink, +TOutputESSL::TOutputESSL(TInfoSinkBase &objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, - NameMap& nameMap, - TSymbolTable& symbolTable, - int shaderVersion) - : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion) + NameMap &nameMap, + TSymbolTable &symbolTable, + int shaderVersion, + bool forceHighp) + : TOutputGLSLBase(objSink, + clampingStrategy, + hashFunction, + nameMap, + symbolTable, + shaderVersion, + SH_ESSL_OUTPUT), + mForceHighp(forceHighp) { } @@ -22,6 +30,9 @@ bool TOutputESSL::writeVariablePrecision(TPrecision precision) return false; TInfoSinkBase& out = objSink(); - out << getPrecisionString(precision); + if (mForceHighp) + out << getPrecisionString(EbpHigh); + else + out << getPrecisionString(precision); return true; } diff --git a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h index 8a567fb8aa..813f1e944b 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef CROSSCOMPILERGLSL_OUTPUTESSL_H_ -#define CROSSCOMPILERGLSL_OUTPUTESSL_H_ +#ifndef COMPILER_TRANSLATOR_OUTPUTESSL_H_ +#define COMPILER_TRANSLATOR_OUTPUTESSL_H_ #include "compiler/translator/OutputGLSLBase.h" @@ -17,10 +17,13 @@ public: ShHashFunction64 hashFunction, NameMap& nameMap, TSymbolTable& symbolTable, - int shaderVersion); + int shaderVersion, + bool forceHighp); protected: virtual bool writeVariablePrecision(TPrecision precision); +private: + bool mForceHighp; }; -#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_ +#endif // COMPILER_TRANSLATOR_OUTPUTESSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp index eb7cbb4ae8..9badf0e2fc 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp @@ -11,8 +11,15 @@ TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink, ShHashFunction64 hashFunction, NameMap& nameMap, TSymbolTable& symbolTable, - int shaderVersion) - : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion) + int shaderVersion, + ShShaderOutput output) + : TOutputGLSLBase(objSink, + clampingStrategy, + hashFunction, + nameMap, + symbolTable, + shaderVersion, + output) { } @@ -21,21 +28,30 @@ bool TOutputGLSL::writeVariablePrecision(TPrecision) return false; } -void TOutputGLSL::visitSymbol(TIntermSymbol* node) +void TOutputGLSL::visitSymbol(TIntermSymbol *node) { TInfoSinkBase& out = objSink(); - if (node->getSymbol() == "gl_FragDepthEXT") + const TString &symbol = node->getSymbol(); + if (symbol == "gl_FragDepthEXT") { out << "gl_FragDepth"; } + else if (symbol == "gl_FragColor" && getShaderOutput() == SH_GLSL_CORE_OUTPUT) + { + out << "webgl_FragColor"; + } + else if (symbol == "gl_FragData" && getShaderOutput() == SH_GLSL_CORE_OUTPUT) + { + out << "webgl_FragData"; + } else { TOutputGLSLBase::visitSymbol(node); } } -TString TOutputGLSL::translateTextureFunction(TString& name) +TString TOutputGLSL::translateTextureFunction(TString &name) { static const char *simpleRename[] = { "texture2DLodEXT", "texture2DLod", @@ -46,10 +62,30 @@ TString TOutputGLSL::translateTextureFunction(TString& name) "textureCubeGradEXT", "textureCubeGradARB", NULL, NULL }; + static const char *legacyToCoreRename[] = { + "texture2D", "texture", + "texture2DProj", "textureProj", + "texture2DLod", "textureLod", + "texture2DProjLod", "textureProjLod", + "textureCube", "texture", + "textureCubeLod", "textureLod", + // Extensions + "texture2DLodEXT", "textureLod", + "texture2DProjLodEXT", "textureProjLod", + "textureCubeLodEXT", "textureLod", + "texture2DGradEXT", "textureGrad", + "texture2DProjGradEXT", "textureProjGrad", + "textureCubeGradEXT", "textureGrad", + NULL, NULL + }; + const char **mapping = (getShaderOutput() == SH_GLSL_CORE_OUTPUT) ? + legacyToCoreRename : simpleRename; - for (int i = 0; simpleRename[i] != NULL; i += 2) { - if (name == simpleRename[i]) { - return simpleRename[i+1]; + for (int i = 0; mapping[i] != NULL; i += 2) + { + if (name == mapping[i]) + { + return mapping[i+1]; } } diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h index bceebe397d..21b2d079d3 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h @@ -4,25 +4,26 @@ // found in the LICENSE file. // -#ifndef CROSSCOMPILERGLSL_OUTPUTGLSL_H_ -#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_ +#ifndef COMPILER_TRANSLATOR_OUTPUTGLSL_H_ +#define COMPILER_TRANSLATOR_OUTPUTGLSL_H_ #include "compiler/translator/OutputGLSLBase.h" class TOutputGLSL : public TOutputGLSLBase { -public: + public: TOutputGLSL(TInfoSinkBase& objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, NameMap& nameMap, TSymbolTable& symbolTable, - int shaderVersion); + int shaderVersion, + ShShaderOutput output); -protected: + protected: virtual bool writeVariablePrecision(TPrecision); virtual void visitSymbol(TIntermSymbol* node); virtual TString translateTextureFunction(TString& name); }; -#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_ +#endif // COMPILER_TRANSLATOR_OUTPUTGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp index ed590967b1..4bb6305d05 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp @@ -36,8 +36,17 @@ bool isSingleStatement(TIntermNode *node) { return false; } + else if (node->getAsSwitchNode()) + { + return false; + } + else if (node->getAsCaseNode()) + { + return false; + } return true; } + } // namespace TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, @@ -45,7 +54,8 @@ TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, ShHashFunction64 hashFunction, NameMap &nameMap, TSymbolTable &symbolTable, - int shaderVersion) + int shaderVersion, + ShShaderOutput output) : TIntermTraverser(true, true, true), mObjSink(objSink), mDeclaringVariables(false), @@ -53,7 +63,8 @@ TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, mHashFunction(hashFunction), mNameMap(nameMap), mSymbolTable(symbolTable), - mShaderVersion(shaderVersion) + mShaderVersion(shaderVersion), + mOutput(output) { } @@ -83,7 +94,34 @@ void TOutputGLSLBase::writeVariableType(const TType &type) TQualifier qualifier = type.getQualifier(); if (qualifier != EvqTemporary && qualifier != EvqGlobal) { - out << type.getQualifierString() << " "; + if (mOutput == SH_GLSL_CORE_OUTPUT) + { + switch (qualifier) + { + case EvqAttribute: + out << "in" << " "; + break; + case EvqVaryingIn: + out << "in" << " "; + break; + case EvqVaryingOut: + out << "out" << " "; + break; + case EvqInvariantVaryingIn: + out << "invariant in" << " "; + break; + case EvqInvariantVaryingOut: + out << "invariant out" << " "; + break; + default: + out << type.getQualifierString() << " "; + break; + } + } + else + { + out << type.getQualifierString() << " "; + } } // Declare the struct if we have not done so already. if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) @@ -166,6 +204,9 @@ const ConstantUnion *TOutputGLSLBase::writeConstantUnion( case EbtInt: out << pConstUnion->getIConst(); break; + case EbtUInt: + out << pConstUnion->getUConst() << "u"; + break; case EbtBool: out << pConstUnion->getBConst(); break; @@ -223,6 +264,9 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; + case EOpIModAssign: + writeTriplet(visit, "(", " %= ", ")"); + break; // Notice the fall-through. case EOpMulAssign: case EOpVectorTimesMatrixAssign: @@ -231,6 +275,21 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) case EOpMatrixTimesMatrixAssign: writeTriplet(visit, "(", " *= ", ")"); break; + case EOpBitShiftLeftAssign: + writeTriplet(visit, "(", " <<= ", ")"); + break; + case EOpBitShiftRightAssign: + writeTriplet(visit, "(", " >>= ", ")"); + break; + case EOpBitwiseAndAssign: + writeTriplet(visit, "(", " &= ", ")"); + break; + case EOpBitwiseXorAssign: + writeTriplet(visit, "(", " ^= ", ")"); + break; + case EOpBitwiseOrAssign: + writeTriplet(visit, "(", " |= ", ")"); + break; case EOpIndexDirect: writeTriplet(visit, NULL, "[", "]"); @@ -340,9 +399,25 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; - case EOpMod: - UNIMPLEMENTED(); + case EOpIMod: + writeTriplet(visit, "(", " % ", ")"); + break; + case EOpBitShiftLeft: + writeTriplet(visit, "(", " << ", ")"); break; + case EOpBitShiftRight: + writeTriplet(visit, "(", " >> ", ")"); + break; + case EOpBitwiseAnd: + writeTriplet(visit, "(", " & ", ")"); + break; + case EOpBitwiseXor: + writeTriplet(visit, "(", " ^ ", ")"); + break; + case EOpBitwiseOr: + writeTriplet(visit, "(", " | ", ")"); + break; + case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; @@ -398,6 +473,7 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) case EOpPositive: preString = "(+"; break; case EOpVectorLogicalNot: preString = "not("; break; case EOpLogicalNot: preString = "(!"; break; + case EOpBitwiseNot: preString = "(~"; break; case EOpPostIncrement: preString = "("; postString = "++)"; break; case EOpPostDecrement: preString = "("; postString = "--)"; break; @@ -429,6 +505,25 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) preString = "atan("; break; + case EOpSinh: + preString = "sinh("; + break; + case EOpCosh: + preString = "cosh("; + break; + case EOpTanh: + preString = "tanh("; + break; + case EOpAsinh: + preString = "asinh("; + break; + case EOpAcosh: + preString = "acosh("; + break; + case EOpAtanh: + preString = "atanh("; + break; + case EOpExp: preString = "exp("; break; @@ -457,12 +552,59 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) case EOpFloor: preString = "floor("; break; + case EOpTrunc: + preString = "trunc("; + break; + case EOpRound: + preString = "round("; + break; + case EOpRoundEven: + preString = "roundEven("; + break; case EOpCeil: preString = "ceil("; break; case EOpFract: preString = "fract("; break; + case EOpIsNan: + preString = "isnan("; + break; + case EOpIsInf: + preString = "isinf("; + break; + + case EOpFloatBitsToInt: + preString = "floatBitsToInt("; + break; + case EOpFloatBitsToUint: + preString = "floatBitsToUint("; + break; + case EOpIntBitsToFloat: + preString = "intBitsToFloat("; + break; + case EOpUintBitsToFloat: + preString = "uintBitsToFloat("; + break; + + case EOpPackSnorm2x16: + preString = "packSnorm2x16("; + break; + case EOpPackUnorm2x16: + preString = "packUnorm2x16("; + break; + case EOpPackHalf2x16: + preString = "packHalf2x16("; + break; + case EOpUnpackSnorm2x16: + preString = "unpackSnorm2x16("; + break; + case EOpUnpackUnorm2x16: + preString = "unpackUnorm2x16("; + break; + case EOpUnpackHalf2x16: + preString = "unpackHalf2x16("; + break; case EOpLength: preString = "length("; @@ -481,6 +623,16 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) preString = "fwidth("; break; + case EOpTranspose: + preString = "transpose("; + break; + case EOpDeterminant: + preString = "determinant("; + break; + case EOpInverse: + preString = "inverse("; + break; + case EOpAny: preString = "any("; break; @@ -536,6 +688,36 @@ bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node) return false; } +bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node) +{ + if (node->getStatementList()) + { + writeTriplet(visit, "switch (", ") ", nullptr); + // The curly braces get written when visiting the statementList aggregate + } + else + { + // No statementList, so it won't output curly braces + writeTriplet(visit, "switch (", ") {", "}\n"); + } + return true; +} + +bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node) +{ + if (node->hasCondition()) + { + writeTriplet(visit, "case (", nullptr, "):\n"); + return true; + } + else + { + TInfoSinkBase &out = objSink(); + out << "default:\n"; + return false; + } +} + bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) { bool visitChildren = true; @@ -555,11 +737,11 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); iter != node->getSequence()->end(); ++iter) { - TIntermNode *node = *iter; - ASSERT(node != NULL); - node->traverse(this); + TIntermNode *curNode = *iter; + ASSERT(curNode != NULL); + curNode->traverse(this); - if (isSingleStatement(node)) + if (isSingleStatement(curNode)) out << ";\n"; } decrementDepth(); @@ -622,6 +804,15 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) else out << ")"; break; + case EOpInternalFunctionCall: + // Function call to an internal helper function. + if (visit == PreVisit) + out << node->getName() << "("; + else if (visit == InVisit) + out << ", "; + else + out << ")"; + break; case EOpParameters: // Function parameters. ASSERT(visit == PreVisit); @@ -724,6 +915,10 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) } break; + case EOpOuterProduct: + writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction); + break; + case EOpLessThan: writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction); break; @@ -749,6 +944,9 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) case EOpMod: writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction); break; + case EOpModf: + writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction); + break; case EOpPow: writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction); break; diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h index e5174f5660..4e66059c21 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ -#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ +#ifndef COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ +#define COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ #include @@ -21,7 +21,13 @@ class TOutputGLSLBase : public TIntermTraverser ShHashFunction64 hashFunction, NameMap &nameMap, TSymbolTable& symbolTable, - int shaderVersion); + int shaderVersion, + ShShaderOutput output); + + ShShaderOutput getShaderOutput() const + { + return mOutput; + } protected: TInfoSinkBase &objSink() { return mObjSink; } @@ -37,6 +43,8 @@ class TOutputGLSLBase : public TIntermTraverser virtual bool visitBinary(Visit visit, TIntermBinary *node); virtual bool visitUnary(Visit visit, TIntermUnary *node); virtual bool visitSelection(Visit visit, TIntermSelection *node); + virtual bool visitSwitch(Visit visit, TIntermSwitch *node); + virtual bool visitCase(Visit visit, TIntermCase *node); virtual bool visitAggregate(Visit visit, TIntermAggregate *node); virtual bool visitLoop(Visit visit, TIntermLoop *node); virtual bool visitBranch(Visit visit, TIntermBranch *node); @@ -78,6 +86,8 @@ class TOutputGLSLBase : public TIntermTraverser TSymbolTable &mSymbolTable; const int mShaderVersion; + + ShShaderOutput mOutput; }; -#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ +#endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp index 30bbbff0f5..94225b81c4 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp @@ -6,26 +6,29 @@ #include "compiler/translator/OutputHLSL.h" +#include +#include +#include + #include "common/angleutils.h" #include "common/utilities.h" -#include "common/blocklayout.h" -#include "compiler/translator/compilerdebug.h" -#include "compiler/translator/InfoSink.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" #include "compiler/translator/DetectDiscontinuity.h" -#include "compiler/translator/SearchSymbol.h" -#include "compiler/translator/UnfoldShortCircuit.h" #include "compiler/translator/FlagStd140Structs.h" +#include "compiler/translator/InfoSink.h" #include "compiler/translator/NodeSearch.h" +#include "compiler/translator/RemoveSwitchFallThrough.h" #include "compiler/translator/RewriteElseBlocks.h" -#include "compiler/translator/UtilsHLSL.h" -#include "compiler/translator/util.h" -#include "compiler/translator/UniformHLSL.h" +#include "compiler/translator/SearchSymbol.h" #include "compiler/translator/StructureHLSL.h" #include "compiler/translator/TranslatorHLSL.h" - -#include -#include -#include +#include "compiler/translator/UnfoldShortCircuit.h" +#include "compiler/translator/UniformHLSL.h" +#include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/blocklayout.h" +#include "compiler/translator/compilerdebug.h" +#include "compiler/translator/util.h" namespace sh { @@ -94,12 +97,21 @@ bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const return false; } -OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator) +OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, ShShaderOutput outputType, + int numRenderTargets, const std::vector &uniforms, + int compileOptions) : TIntermTraverser(true, true, true), - mContext(context), - mOutputType(parentTranslator->getOutputType()) + mShaderType(shaderType), + mShaderVersion(shaderVersion), + mExtensionBehavior(extensionBehavior), + mSourcePath(sourcePath), + mOutputType(outputType), + mNumRenderTargets(numRenderTargets), + mCompileOptions(compileOptions) { - mUnfoldShortCircuit = new UnfoldShortCircuit(context, this); + mUnfoldShortCircuit = new UnfoldShortCircuit(this); mInsideFunction = false; mUsesFragColor = false; @@ -109,28 +121,12 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator) mUsesPointCoord = false; mUsesFrontFacing = false; mUsesPointSize = false; + mUsesInstanceID = false; mUsesFragDepth = false; mUsesXor = false; - mUsesMod1 = false; - mUsesMod2v = false; - mUsesMod2f = false; - mUsesMod3v = false; - mUsesMod3f = false; - mUsesMod4v = false; - mUsesMod4f = false; - mUsesFaceforward1 = false; - mUsesFaceforward2 = false; - mUsesFaceforward3 = false; - mUsesFaceforward4 = false; - mUsesAtan2_1 = false; - mUsesAtan2_2 = false; - mUsesAtan2_3 = false; - mUsesAtan2_4 = false; mUsesDiscardRewriting = false; mUsesNestedBreak = false; - - const ShBuiltInResources &resources = parentTranslator->getResources(); - mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; + mRequiresIEEEStrictCompiling = false; mUniqueIndex = 0; @@ -143,20 +139,14 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator) mExcessiveLoopIndex = NULL; mStructureHLSL = new StructureHLSL; - mUniformHLSL = new UniformHLSL(mStructureHLSL, parentTranslator); + mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms); if (mOutputType == SH_HLSL9_OUTPUT) { - if (mContext.shaderType == GL_FRAGMENT_SHADER) - { - // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront - mUniformHLSL->reserveUniformRegisters(3); - } - else - { - // Reserve registers for dx_DepthRange and dx_ViewAdjust - mUniformHLSL->reserveUniformRegisters(2); - } + // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront. + // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and dx_ViewAdjust. + // In both cases total 3 uniform registers need to be reserved. + mUniformHLSL->reserveUniformRegisters(3); } // Reserve registers for the default uniform block and driver constants @@ -168,27 +158,55 @@ OutputHLSL::~OutputHLSL() SafeDelete(mUnfoldShortCircuit); SafeDelete(mStructureHLSL); SafeDelete(mUniformHLSL); + for (auto it = mStructEqualityFunctions.begin(); it != mStructEqualityFunctions.end(); ++it) + { + SafeDelete(*it); + } + for (auto it = mArrayEqualityFunctions.begin(); it != mArrayEqualityFunctions.end(); ++it) + { + SafeDelete(*it); + } } -void OutputHLSL::output() +void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink) { - mContainsLoopDiscontinuity = mContext.shaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot); - mContainsAnyLoop = containsAnyLoop(mContext.treeRoot); - const std::vector &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot); + mContainsLoopDiscontinuity = mShaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(treeRoot); + mContainsAnyLoop = containsAnyLoop(treeRoot); + const std::vector &flaggedStructs = FlagStd140ValueStructs(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 == GL_VERTEX_SHADER) + if (mOutputType == SH_HLSL9_OUTPUT && mShaderType == GL_VERTEX_SHADER) + { + RewriteElseBlocks(treeRoot); + } + + BuiltInFunctionEmulator builtInFunctionEmulator; + InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator); + builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot); + + // Output the body and footer first to determine what has to go in the header + mInfoSinkStack.push(&mBody); + treeRoot->traverse(this); + mInfoSinkStack.pop(); + + mInfoSinkStack.push(&mFooter); + if (!mDeferredGlobalInitializers.empty()) { - RewriteElseBlocks(mContext.treeRoot); + writeDeferredGlobalInitializers(mFooter); } + mInfoSinkStack.pop(); + + mInfoSinkStack.push(&mHeader); + header(&builtInFunctionEmulator); + mInfoSinkStack.pop(); - mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header - header(); + objSink << mHeader.c_str(); + objSink << mBody.c_str(); + objSink << mFooter.c_str(); - mContext.infoSink().obj << mHeader.c_str(); - mContext.infoSink().obj << mBody.c_str(); + builtInFunctionEmulator.Cleanup(); } void OutputHLSL::makeFlaggedStructMaps(const std::vector &flaggedStructs) @@ -197,10 +215,14 @@ void OutputHLSL::makeFlaggedStructMaps(const std::vector &flagge { TIntermTyped *flaggedNode = flaggedStructs[structIndex]; + TInfoSinkBase structInfoSink; + mInfoSinkStack.push(&structInfoSink); + // This will mark the necessary block elements as referenced flaggedNode->traverse(this); - TString structName(mBody.c_str()); - mBody.erase(); + + TString structName(structInfoSink.c_str()); + mInfoSinkStack.pop(); mFlaggedStructOriginalNames[flaggedNode] = structName; @@ -213,11 +235,6 @@ void OutputHLSL::makeFlaggedStructMaps(const std::vector &flagge } } -TInfoSinkBase &OutputHLSL::getBodyStream() -{ - return mBody; -} - const std::map &OutputHLSL::getInterfaceBlockRegisterMap() const { return mUniformHLSL->getInterfaceBlockRegisterMap(); @@ -277,9 +294,9 @@ TString OutputHLSL::structInitializerString(int indent, const TStructure &struct return init; } -void OutputHLSL::header() +void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator) { - TInfoSinkBase &out = mHeader; + TInfoSinkBase &out = getInfoSink(); TString varyings; TString attributes; @@ -320,6 +337,23 @@ void OutputHLSL::header() out << mUniformHLSL->uniformsHeader(mOutputType, mReferencedUniforms); out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks); + if (!mEqualityFunctions.empty()) + { + out << "\n// Equality functions\n\n"; + for (auto it = mEqualityFunctions.cbegin(); it != mEqualityFunctions.cend(); ++it) + { + out << (*it)->functionDefinition << "\n"; + } + } + if (!mArrayAssignmentFunctions.empty()) + { + out << "\n// Assignment functions\n\n"; + for (auto it = mArrayAssignmentFunctions.cbegin(); it != mArrayAssignmentFunctions.cend(); ++it) + { + out << it->functionDefinition << "\n"; + } + } + if (mUsesDiscardRewriting) { out << "#define ANGLE_USES_DISCARD_REWRITING\n"; @@ -330,6 +364,11 @@ void OutputHLSL::header() out << "#define ANGLE_USES_NESTED_BREAK\n"; } + if (mRequiresIEEEStrictCompiling) + { + out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n"; + } + out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n" "#define LOOP [loop]\n" "#define FLATTEN [flatten]\n" @@ -338,16 +377,16 @@ void OutputHLSL::header() "#define FLATTEN\n" "#endif\n"; - if (mContext.shaderType == GL_FRAGMENT_SHADER) + if (mShaderType == 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)); + TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers"); + const bool usingMRTExtension = (iter != mExtensionBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire)); out << "// Varyings\n"; out << varyings; out << "\n"; - if (mContext.getShaderVersion() >= 300) + if (mShaderVersion >= 300) { for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++) { @@ -493,6 +532,11 @@ void OutputHLSL::header() out << "static float gl_PointSize = float(1);\n"; } + if (mUsesInstanceID) + { + out << "static int gl_InstanceID;"; + } + out << "\n" "// Varyings\n"; out << varyings; @@ -511,14 +555,22 @@ void OutputHLSL::header() if (mOutputType == SH_HLSL11_OUTPUT) { + out << "cbuffer DriverConstants : register(b1)\n" + "{\n"; + if (mUsesDepthRange) { - out << "cbuffer DriverConstants : register(b1)\n" - "{\n" - " float3 dx_DepthRange : packoffset(c0);\n" - "};\n" - "\n"; + out << " float3 dx_DepthRange : packoffset(c0);\n"; } + + // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9 shaders. + // However, we declare it for all shaders (including Feature Level 10+). + // The bytecode is the same whether we declare it or not, since D3DCompiler removes it if it's unused. + out << " float4 dx_ViewAdjust : packoffset(c1);\n"; + out << " float2 dx_ViewCoords : packoffset(c2);\n"; + + out << "};\n" + "\n"; } else { @@ -527,7 +579,8 @@ void OutputHLSL::header() out << "uniform float3 dx_DepthRange : register(c0);\n"; } - out << "uniform float4 dx_ViewAdjust : register(c1);\n" + out << "uniform float4 dx_ViewAdjust : register(c1);\n"; + out << "uniform float2 dx_ViewCoords : register(c2);\n" "\n"; } @@ -980,7 +1033,15 @@ void OutputHLSL::header() } else if (IsShadowSampler(textureFunction->sampler)) { - out << "x.SampleCmp(s, "; + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: out << "x.SampleCmp(s, "; break; + case TextureFunction::BIAS: out << "x.SampleCmp(s, "; break; + case TextureFunction::LOD: out << "x.SampleCmp(s, "; break; + case TextureFunction::LOD0: out << "x.SampleCmpLevelZero(s, "; break; + case TextureFunction::LOD0BIAS: out << "x.SampleCmpLevelZero(s, "; break; + default: UNREACHABLE(); + } } else { @@ -1111,11 +1172,20 @@ void OutputHLSL::header() else if (IsShadowSampler(textureFunction->sampler)) { // Compare value - switch(textureFunction->coords) + if (textureFunction->proj) { - case 3: out << "), t.z"; break; - case 4: out << "), t.w"; break; - default: UNREACHABLE(); + // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: + // The resulting third component of P' in the shadow forms is used as Dref + out << "), t.z" << proj; + } + else + { + switch(textureFunction->coords) + { + case 3: out << "), t.z"; break; + case 4: out << "), t.w"; break; + default: UNREACHABLE(); + } } } else @@ -1131,11 +1201,20 @@ void OutputHLSL::header() else if (IsShadowSampler(textureFunction->sampler)) { // Compare value - switch(textureFunction->coords) + if (textureFunction->proj) { - case 3: out << "), t.z"; break; - case 4: out << "), t.w"; break; - default: UNREACHABLE(); + // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: + // The resulting third component of P' in the shadow forms is used as Dref + out << "), t.z" << proj; + } + else + { + switch(textureFunction->coords) + { + case 3: out << "), t.z"; break; + case 4: out << "), t.w"; break; + default: UNREACHABLE(); + } } } else @@ -1205,179 +1284,12 @@ void OutputHLSL::header() "\n"; } - if (mUsesMod1) - { - out << "float mod(float x, float y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"; - } - - if (mUsesMod2v) - { - out << "float2 mod(float2 x, float2 y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"; - } - - if (mUsesMod2f) - { - out << "float2 mod(float2 x, float y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"; - } - - if (mUsesMod3v) - { - out << "float3 mod(float3 x, float3 y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"; - } - - if (mUsesMod3f) - { - out << "float3 mod(float3 x, float y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"; - } - - if (mUsesMod4v) - { - out << "float4 mod(float4 x, float4 y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"; - } - - if (mUsesMod4f) - { - out << "float4 mod(float4 x, float y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"; - } - - if (mUsesFaceforward1) - { - out << "float faceforward(float N, float I, float Nref)\n" - "{\n" - " if(dot(Nref, I) >= 0)\n" - " {\n" - " return -N;\n" - " }\n" - " else\n" - " {\n" - " return N;\n" - " }\n" - "}\n" - "\n"; - } - - if (mUsesFaceforward2) - { - out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n" - "{\n" - " if(dot(Nref, I) >= 0)\n" - " {\n" - " return -N;\n" - " }\n" - " else\n" - " {\n" - " return N;\n" - " }\n" - "}\n" - "\n"; - } - - if (mUsesFaceforward3) - { - out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n" - "{\n" - " if(dot(Nref, I) >= 0)\n" - " {\n" - " return -N;\n" - " }\n" - " else\n" - " {\n" - " return N;\n" - " }\n" - "}\n" - "\n"; - } - - if (mUsesFaceforward4) - { - out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n" - "{\n" - " if(dot(Nref, I) >= 0)\n" - " {\n" - " return -N;\n" - " }\n" - " else\n" - " {\n" - " return N;\n" - " }\n" - "}\n" - "\n"; - } - - if (mUsesAtan2_1) - { - out << "float atanyx(float y, float x)\n" - "{\n" - " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN - " return atan2(y, x);\n" - "}\n"; - } - - if (mUsesAtan2_2) - { - out << "float2 atanyx(float2 y, float2 x)\n" - "{\n" - " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" - " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" - " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n" - "}\n"; - } - - if (mUsesAtan2_3) - { - out << "float3 atanyx(float3 y, float3 x)\n" - "{\n" - " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" - " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" - " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" - " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n" - "}\n"; - } - - if (mUsesAtan2_4) - { - out << "float4 atanyx(float4 y, float4 x)\n" - "{\n" - " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" - " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" - " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" - " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n" - " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n" - "}\n"; - } + builtInFunctionEmulator->OutputEmulatedFunctions(out); } void OutputHLSL::visitSymbol(TIntermSymbol *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); // Handle accessing std140 structs by value if (mFlaggedStructMappedNames.count(node) > 0) @@ -1458,6 +1370,11 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) mUsesPointSize = true; out << name; } + else if (qualifier == EvqInstanceID) + { + mUsesInstanceID = true; + out << name; + } else if (name == "gl_FragDepthEXT") { mUsesFragDepth = true; @@ -1476,12 +1393,51 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) void OutputHLSL::visitRaw(TIntermRaw *node) { - mBody << node->getRawText(); + getInfoSink() << node->getRawText(); +} + +void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out) +{ + if (type.isScalar() && !type.isArray()) + { + if (op == EOpEqual) + { + outputTriplet(visit, "(", " == ", ")", out); + } + else + { + outputTriplet(visit, "(", " != ", ")", out); + } + } + else + { + if (visit == PreVisit && op == EOpNotEqual) + { + out << "!"; + } + + if (type.isArray()) + { + const TString &functionName = addArrayEqualityFunction(type); + outputTriplet(visit, (functionName + "(").c_str(), ", ", ")", out); + } + else if (type.getBasicType() == EbtStruct) + { + const TStructure &structure = *type.getStruct(); + const TString &functionName = addStructEqualityFunction(structure); + outputTriplet(visit, (functionName + "(").c_str(), ", ", ")", out); + } + else + { + ASSERT(type.isMatrix() || type.isVector()); + outputTriplet(visit, "all(", " == ", ")", out); + } + } } bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); // Handle accessing std140 structs by value if (mFlaggedStructMappedNames.count(node) > 0) @@ -1492,7 +1448,17 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) switch (node->getOp()) { - case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break; + case EOpAssign: + if (node->getLeft()->isArray()) + { + const TString &functionName = addArrayAssignmentFunction(node->getType()); + outputTriplet(visit, (functionName + "(").c_str(), ", ", ")"); + } + else + { + outputTriplet(visit, "(", " = ", ")"); + } + break; case EOpInitialize: if (visit == PreVisit) { @@ -1502,22 +1468,21 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) // this to "float t = x, x = t;". TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); + ASSERT(symbolNode); TIntermTyped *expression = node->getRight(); - sh::SearchSymbol searchSymbol(symbolNode->getSymbol()); - expression->traverse(&searchSymbol); - bool sameSymbol = searchSymbol.foundMatch(); - - if (sameSymbol) + // TODO (jmadill): do a 'deep' scan to know if an expression is statically const + if (symbolNode->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst) { - // Type already printed - out << "t" + str(mUniqueIndex) + " = "; - expression->traverse(this); - out << ", "; - symbolNode->traverse(this); - out << " = t" + str(mUniqueIndex); - - mUniqueIndex++; + // For variables which are not constant, defer their real initialization until + // after we initialize other globals: uniforms, attributes and varyings. + mDeferredGlobalInitializers.push_back(std::make_pair(symbolNode, expression)); + const TString &initString = initializer(node->getType()); + node->setRight(new TIntermRaw(node->getType(), initString)); + } + else if (writeSameSymbolInitializer(out, symbolNode, expression)) + { + // Skip initializing the rest of the expression return false; } } @@ -1554,16 +1519,22 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) } else if (visit == InVisit) { - out << " = mul("; + out << " = transpose(mul(transpose("; node->getLeft()->traverse(this); - out << ", "; + out << "), transpose("; } else { - out << "))"; + out << "))))"; } break; case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break; + case EOpIModAssign: outputTriplet(visit, "(", " %= ", ")"); break; + case EOpBitShiftLeftAssign: outputTriplet(visit, "(", " <<= ", ")"); break; + case EOpBitShiftRightAssign: outputTriplet(visit, "(", " >>= ", ")"); break; + case EOpBitwiseAndAssign: outputTriplet(visit, "(", " &= ", ")"); break; + case EOpBitwiseXorAssign: outputTriplet(visit, "(", " ^= ", ")"); break; + case EOpBitwiseOrAssign: outputTriplet(visit, "(", " |= ", ")"); break; case EOpIndexDirect: { const TType& leftType = node->getLeft()->getType(); @@ -1651,65 +1622,15 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) case EOpSub: outputTriplet(visit, "(", " - ", ")"); break; case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break; + case EOpIMod: outputTriplet(visit, "(", " % ", ")"); break; + case EOpBitShiftLeft: outputTriplet(visit, "(", " << ", ")"); break; + case EOpBitShiftRight: outputTriplet(visit, "(", " >> ", ")"); break; + case EOpBitwiseAnd: outputTriplet(visit, "(", " & ", ")"); break; + case EOpBitwiseXor: outputTriplet(visit, "(", " ^ ", ")"); break; + case EOpBitwiseOr: outputTriplet(visit, "(", " | ", ")"); break; case EOpEqual: case EOpNotEqual: - if (node->getLeft()->isScalar()) - { - if (node->getOp() == EOpEqual) - { - outputTriplet(visit, "(", " == ", ")"); - } - else - { - outputTriplet(visit, "(", " != ", ")"); - } - } - else if (node->getLeft()->getBasicType() == EbtStruct) - { - if (node->getOp() == EOpEqual) - { - out << "("; - } - else - { - out << "!("; - } - - 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(), structure) + " == "; - node->getRight()->traverse(this); - out << "." + DecorateField(field->name(), structure); - - if (i < fields.size() - 1) - { - out << " && "; - } - } - - out << ")"; - - return false; - } - else - { - ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector()); - - if (node->getOp() == EOpEqual) - { - outputTriplet(visit, "all(", " == ", ")"); - } - else - { - outputTriplet(visit, "!all(", " == ", ")"); - } - } + outputEqual(visit, node->getLeft()->getType(), node->getOp(), out); break; case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; @@ -1760,6 +1681,7 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) case EOpPositive: outputTriplet(visit, "(+", "", ")"); break; case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break; case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break; + case EOpBitwiseNot: outputTriplet(visit, "(~", "", ")"); break; case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break; case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break; case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break; @@ -1772,6 +1694,21 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break; case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break; case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break; + case EOpSinh: outputTriplet(visit, "sinh(", "", ")"); break; + case EOpCosh: outputTriplet(visit, "cosh(", "", ")"); break; + case EOpTanh: outputTriplet(visit, "tanh(", "", ")"); break; + case EOpAsinh: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "asinh("); + break; + case EOpAcosh: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "acosh("); + break; + case EOpAtanh: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "atanh("); + break; case EOpExp: outputTriplet(visit, "exp(", "", ")"); break; case EOpLog: outputTriplet(visit, "log(", "", ")"); break; case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break; @@ -1781,8 +1718,47 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break; case EOpSign: outputTriplet(visit, "sign(", "", ")"); break; case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break; + case EOpTrunc: outputTriplet(visit, "trunc(", "", ")"); break; + case EOpRound: outputTriplet(visit, "round(", "", ")"); break; + case EOpRoundEven: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "roundEven("); + break; case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break; case EOpFract: outputTriplet(visit, "frac(", "", ")"); break; + case EOpIsNan: + outputTriplet(visit, "isnan(", "", ")"); + mRequiresIEEEStrictCompiling = true; + break; + case EOpIsInf: outputTriplet(visit, "isinf(", "", ")"); break; + case EOpFloatBitsToInt: outputTriplet(visit, "asint(", "", ")"); break; + case EOpFloatBitsToUint: outputTriplet(visit, "asuint(", "", ")"); break; + case EOpIntBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break; + case EOpUintBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break; + case EOpPackSnorm2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "packSnorm2x16("); + break; + case EOpPackUnorm2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "packUnorm2x16("); + break; + case EOpPackHalf2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "packHalf2x16("); + break; + case EOpUnpackSnorm2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "unpackSnorm2x16("); + break; + case EOpUnpackUnorm2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "unpackUnorm2x16("); + break; + case EOpUnpackHalf2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "unpackHalf2x16("); + break; case EOpLength: outputTriplet(visit, "length(", "", ")"); break; case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break; case EOpDFdx: @@ -1815,6 +1791,13 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) outputTriplet(visit, "fwidth(", "", ")"); } break; + case EOpTranspose: outputTriplet(visit, "transpose(", "", ")"); break; + case EOpDeterminant: outputTriplet(visit, "determinant(transpose(", "", "))"); break; + case EOpInverse: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "inverse("); + break; + case EOpAny: outputTriplet(visit, "any(", "", ")"); break; case EOpAll: outputTriplet(visit, "all(", "", ")"); break; default: UNREACHABLE(); @@ -1825,7 +1808,7 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); switch (node->getOp()) { @@ -1843,7 +1826,11 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) traverseStatements(*sit); - out << ";\n"; + // Don't output ; after case labels, they're terminated by : + // This is needed especially since outputting a ; after a case statement would turn empty + // case statements into non-empty case statements, disallowing fall-through from them. + if ((*sit)->getAsCaseNode() == nullptr) + out << ";\n"; } if (mInsideFunction) @@ -1871,11 +1858,12 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration { - for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) + for (auto it = sequence->cbegin(); it != sequence->cend(); ++it) { - if (isSingleStatement(*sit)) + const auto &seqElement = *it; + if (isSingleStatement(seqElement)) { - mUnfoldShortCircuit->traverse(*sit); + mUnfoldShortCircuit->traverse(seqElement); } if (!mInsideFunction) @@ -1885,7 +1873,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) out << TypeString(variable->getType()) + " "; - TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); + TIntermSymbol *symbol = seqElement->getAsSymbolNode(); if (symbol) { @@ -1895,10 +1883,10 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) } else { - (*sit)->traverse(this); + seqElement->traverse(this); } - if (*sit != sequence->back()) + if (seqElement != sequence->back()) { out << ";\n"; } @@ -2149,7 +2137,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) bool bias = (arguments->size() > mandatoryArgumentCount); // Bias argument is optional - if (lod0 || mContext.shaderType == GL_VERTEX_SHADER) + if (lod0 || mShaderType == GL_VERTEX_SHADER) { if (bias) { @@ -2217,7 +2205,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) { const TString &structName = StructNameString(*node->getType().getStruct()); mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence()); - outputTriplet(visit, structName + "_ctor(", ", ", ")"); + outputTriplet(visit, (structName + "_ctor(").c_str(), ", ", ")"); } break; case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; @@ -2227,37 +2215,15 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break; case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break; case EOpMod: - { - // We need to look at the number of components in both arguments - 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; - case 21: mUsesMod2f = true; break; - case 33: mUsesMod3v = true; break; - case 31: mUsesMod3f = true; break; - case 44: mUsesMod4v = true; break; - case 41: mUsesMod4f = true; break; - default: UNREACHABLE(); - } - - outputTriplet(visit, "mod(", ", ", ")"); - } + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "mod("); break; + case EOpModf: outputTriplet(visit, "modf(", ", ", ")"); 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()) - { - case 1: mUsesAtan2_1 = true; break; - case 2: mUsesAtan2_2 = true; break; - case 3: mUsesAtan2_3 = true; break; - case 4: mUsesAtan2_4 = true; break; - default: UNREACHABLE(); - } - outputTriplet(visit, "atanyx(", ", ", ")"); + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "atan("); break; case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break; case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break; @@ -2269,21 +2235,15 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break; case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break; case EOpFaceForward: - { - switch ((*node->getSequence())[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument - { - case 1: mUsesFaceforward1 = true; break; - case 2: mUsesFaceforward2 = true; break; - case 3: mUsesFaceforward3 = true; break; - case 4: mUsesFaceforward4 = true; break; - default: UNREACHABLE(); - } - - outputTriplet(visit, "faceforward(", ", ", ")"); - } + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "faceforward("); break; case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break; case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break; + case EOpOuterProduct: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "outerProduct("); + break; case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; default: UNREACHABLE(); } @@ -2293,7 +2253,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); if (node->usesTernaryOperator()) { @@ -2307,7 +2267,7 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) // however flattening all the ifs in branch heavy shaders made D3D error too. // As a temporary workaround we flatten the ifs only if there is at least a loop // present somewhere in the shader. - if (mContext.shaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop) + if (mShaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop) { out << "FLATTEN "; } @@ -2361,6 +2321,37 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) return false; } +bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node) +{ + if (node->getStatementList()) + { + node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList())); + outputTriplet(visit, "switch (", ") ", ""); + // The curly braces get written when visiting the statementList aggregate + } + else + { + // No statementList, so it won't output curly braces + outputTriplet(visit, "switch (", ") {", "}\n"); + } + return true; +} + +bool OutputHLSL::visitCase(Visit visit, TIntermCase *node) +{ + if (node->hasCondition()) + { + outputTriplet(visit, "case (", "", "):\n"); + return true; + } + else + { + TInfoSinkBase &out = getInfoSink(); + out << "default:\n"; + return false; + } +} + void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node) { writeConstantUnion(node->getType(), node->getUnionArrayPointer()); @@ -2388,7 +2379,7 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) } } - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); if (node->getType() == ELoopDoWhile) { @@ -2454,7 +2445,7 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); switch (node->getFlowOp()) { @@ -2556,7 +2547,7 @@ bool OutputHLSL::isSingleStatement(TIntermNode *node) bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) { const int MAX_LOOP_ITERATIONS = 254; - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); // Parse loops of the form: // for(int index = initial; index [comparator] limit; index += increment) @@ -2756,10 +2747,8 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) return false; // Not handled as an excessive loop } -void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString) +void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString, TInfoSinkBase &out) { - TInfoSinkBase &out = mBody; - if (visit == PreVisit) { out << preString; @@ -2774,19 +2763,26 @@ void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TStr } } +void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString) +{ + outputTriplet(visit, preString, inString, postString, getInfoSink()); +} + void OutputHLSL::outputLineDirective(int line) { - if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0)) + if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0)) { - mBody << "\n"; - mBody << "#line " << line; + TInfoSinkBase &out = getInfoSink(); + + out << "\n"; + out << "#line " << line; - if (mContext.sourcePath) + if (mSourcePath) { - mBody << " \"" << mContext.sourcePath << "\""; + out << " \"" << mSourcePath << "\""; } - mBody << "\n"; + out << "\n"; } } @@ -2832,15 +2828,15 @@ TString OutputHLSL::initializer(const TType &type) return "{" + string + "}"; } -void OutputHLSL::outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters) +void OutputHLSL::outputConstructor(Visit visit, const TType &type, const char *name, const TIntermSequence *parameters) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); if (visit == PreVisit) { mStructureHLSL->addConstructor(type, name, parameters); - out << name + "("; + out << name << "("; } else if (visit == InVisit) { @@ -2854,7 +2850,7 @@ void OutputHLSL::outputConstructor(Visit visit, const TType &type, const TString const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); const TStructure* structure = type.getStruct(); if (structure) @@ -2912,4 +2908,209 @@ const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const Con return constUnion; } +void OutputHLSL::writeEmulatedFunctionTriplet(Visit visit, const char *preStr) +{ + TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr); + outputTriplet(visit, preString.c_str(), ", ", ")"); +} + +bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression) +{ + sh::SearchSymbol searchSymbol(symbolNode->getSymbol()); + expression->traverse(&searchSymbol); + + if (searchSymbol.foundMatch()) + { + // Type already printed + out << "t" + str(mUniqueIndex) + " = "; + expression->traverse(this); + out << ", "; + symbolNode->traverse(this); + out << " = t" + str(mUniqueIndex); + + mUniqueIndex++; + return true; + } + + return false; +} + +void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out) +{ + out << "#define ANGLE_USES_DEFERRED_INIT\n" + << "\n" + << "void initializeDeferredGlobals()\n" + << "{\n"; + + for (auto it = mDeferredGlobalInitializers.cbegin(); it != mDeferredGlobalInitializers.cend(); ++it) + { + const auto &deferredGlobal = *it; + TIntermSymbol *symbol = deferredGlobal.first; + TIntermTyped *expression = deferredGlobal.second; + ASSERT(symbol); + ASSERT(symbol->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst); + + out << " " << Decorate(symbol->getSymbol()) << " = "; + + if (!writeSameSymbolInitializer(out, symbol, expression)) + { + ASSERT(mInfoSinkStack.top() == &out); + expression->traverse(this); + } + + out << ";\n"; + } + + out << "}\n" + << "\n"; +} + +TString OutputHLSL::addStructEqualityFunction(const TStructure &structure) +{ + const TFieldList &fields = structure.fields(); + + for (auto it = mStructEqualityFunctions.cbegin(); it != mStructEqualityFunctions.cend(); ++it) + { + auto *eqFunction = *it; + if (eqFunction->structure == &structure) + { + return eqFunction->functionName; + } + } + + const TString &structNameString = StructNameString(structure); + + StructEqualityFunction *function = new StructEqualityFunction(); + function->structure = &structure; + function->functionName = "angle_eq_" + structNameString; + + TInfoSinkBase fnOut; + + fnOut << "bool " << function->functionName << "(" << structNameString << " a, " << structNameString + " b)\n" + << "{\n" + " return "; + + for (size_t i = 0; i < fields.size(); i++) + { + const TField *field = fields[i]; + const TType *fieldType = field->type(); + + const TString &fieldNameA = "a." + Decorate(field->name()); + const TString &fieldNameB = "b." + Decorate(field->name()); + + if (i > 0) + { + fnOut << " && "; + } + + fnOut << "("; + outputEqual(PreVisit, *fieldType, EOpEqual, fnOut); + fnOut << fieldNameA; + outputEqual(InVisit, *fieldType, EOpEqual, fnOut); + fnOut << fieldNameB; + outputEqual(PostVisit, *fieldType, EOpEqual, fnOut); + fnOut << ")"; + } + + fnOut << ";\n" << "}\n"; + + function->functionDefinition = fnOut.c_str(); + + mStructEqualityFunctions.push_back(function); + mEqualityFunctions.push_back(function); + + return function->functionName; +} + +TString OutputHLSL::addArrayEqualityFunction(const TType& type) +{ + for (auto it = mArrayEqualityFunctions.cbegin(); it != mArrayEqualityFunctions.cend(); ++it) + { + const auto &eqFunction = *it; + if (eqFunction->type == type) + { + return eqFunction->functionName; + } + } + + const TString &typeName = TypeString(type); + + ArrayHelperFunction *function = new ArrayHelperFunction(); + function->type = type; + + TInfoSinkBase fnNameOut; + fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName; + function->functionName = fnNameOut.c_str(); + + TType nonArrayType = type; + nonArrayType.clearArrayness(); + + TInfoSinkBase fnOut; + + fnOut << "bool " << function->functionName << "(" + << typeName << " a[" << type.getArraySize() << "], " + << typeName << " b[" << type.getArraySize() << "])\n" + << "{\n" + " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n" + " {\n" + " if ("; + + outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut); + fnOut << "a[i]"; + outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut); + fnOut << "b[i]"; + outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut); + + fnOut << ") { return false; }\n" + " }\n" + " return true;\n" + "}\n"; + + function->functionDefinition = fnOut.c_str(); + + mArrayEqualityFunctions.push_back(function); + mEqualityFunctions.push_back(function); + + return function->functionName; +} + +TString OutputHLSL::addArrayAssignmentFunction(const TType& type) +{ + for (auto it = mArrayAssignmentFunctions.cbegin(); it != mArrayAssignmentFunctions.cend(); ++it) + { + const auto &assignFunction = *it; + if (assignFunction.type == type) + { + return assignFunction.functionName; + } + } + + const TString &typeName = TypeString(type); + + ArrayHelperFunction function; + function.type = type; + + TInfoSinkBase fnNameOut; + fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName; + function.functionName = fnNameOut.c_str(); + + TInfoSinkBase fnOut; + + fnOut << "void " << function.functionName << "(out " + << typeName << " a[" << type.getArraySize() << "], " + << typeName << " b[" << type.getArraySize() << "])\n" + << "{\n" + " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n" + " {\n" + " a[i] = b[i];\n" + " }\n" + "}\n"; + + function.functionDefinition = fnOut.c_str(); + + mArrayAssignmentFunctions.push_back(function); + + return function.functionName; +} + } diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h index 5525e6eaa6..51da877c72 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h @@ -4,18 +4,20 @@ // found in the LICENSE file. // -#ifndef COMPILER_OUTPUTHLSL_H_ -#define COMPILER_OUTPUTHLSL_H_ +#ifndef COMPILER_TRANSLATOR_OUTPUTHLSL_H_ +#define COMPILER_TRANSLATOR_OUTPUTHLSL_H_ #include #include #include +#include #include "angle_gl.h" - #include "compiler/translator/IntermNode.h" #include "compiler/translator/ParseContext.h" +class BuiltInFunctionEmulator; + namespace sh { class UnfoldShortCircuit; @@ -27,20 +29,25 @@ typedef std::map ReferencedSymbols; class OutputHLSL : public TIntermTraverser { public: - OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator); - ~OutputHLSL(); + OutputHLSL(sh::GLenum shaderType, int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, ShShaderOutput outputType, + int numRenderTargets, const std::vector &uniforms, + int compileOptions); - void output(); + ~OutputHLSL(); - TInfoSinkBase &getBodyStream(); + void output(TIntermNode *treeRoot, TInfoSinkBase &objSink); const std::map &getInterfaceBlockRegisterMap() const; const std::map &getUniformRegisterMap() const; static TString initializer(const TType &type); + TInfoSinkBase &getInfoSink() { ASSERT(!mInfoSinkStack.empty()); return *mInfoSinkStack.top(); } + protected: - void header(); + void header(const BuiltInFunctionEmulator *builtInFunctionEmulator); // Visit AST nodes and output their code to the body stream void visitSymbol(TIntermSymbol*); @@ -49,6 +56,8 @@ class OutputHLSL : public TIntermTraverser bool visitBinary(Visit visit, TIntermBinary*); bool visitUnary(Visit visit, TIntermUnary*); bool visitSelection(Visit visit, TIntermSelection*); + bool visitSwitch(Visit visit, TIntermSwitch *); + bool visitCase(Visit visit, TIntermCase *); bool visitAggregate(Visit visit, TIntermAggregate*); bool visitLoop(Visit visit, TIntermLoop*); bool visitBranch(Visit visit, TIntermBranch*); @@ -56,16 +65,39 @@ class OutputHLSL : public TIntermTraverser void traverseStatements(TIntermNode *node); bool isSingleStatement(TIntermNode *node); bool handleExcessiveLoop(TIntermLoop *node); - void outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString); + + // Emit one of three strings depending on traverse phase. Called with literal strings so using const char* instead of TString. + void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString, TInfoSinkBase &out); + void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString); void outputLineDirective(int line); TString argumentString(const TIntermSymbol *symbol); int vectorSize(const TType &type) const; - void outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters); + // Emit constructor. Called with literal names so using const char* instead of TString. + void outputConstructor(Visit visit, const TType &type, const char *name, const TIntermSequence *parameters); const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion); - TParseContext &mContext; + void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out); + + void writeEmulatedFunctionTriplet(Visit visit, const char *preStr); + void makeFlaggedStructMaps(const std::vector &flaggedStructs); + + // Returns true if it found a 'same symbol' initializer (initializer that references the variable it's initting) + bool writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression); + void writeDeferredGlobalInitializers(TInfoSinkBase &out); + + // Returns the function name + TString addStructEqualityFunction(const TStructure &structure); + TString addArrayEqualityFunction(const TType &type); + TString addArrayAssignmentFunction(const TType &type); + + sh::GLenum mShaderType; + int mShaderVersion; + const TExtensionBehavior &mExtensionBehavior; + const char *mSourcePath; const ShShaderOutput mOutputType; + int mCompileOptions; + UnfoldShortCircuit *mUnfoldShortCircuit; bool mInsideFunction; @@ -74,6 +106,11 @@ class OutputHLSL : public TIntermTraverser TInfoSinkBase mBody; TInfoSinkBase mFooter; + // A stack is useful when we want to traverse in the header, or in helper functions, but not always + // write to the body. Instead use an InfoSink stack to keep our current state intact. + // TODO (jmadill): Just passing an InfoSink in function parameters would be simpler. + std::stack mInfoSinkStack; + ReferencedSymbols mReferencedUniforms; ReferencedSymbols mReferencedInterfaceBlocks; ReferencedSymbols mReferencedAttributes; @@ -119,25 +156,13 @@ class OutputHLSL : public TIntermTraverser bool mUsesPointCoord; bool mUsesFrontFacing; bool mUsesPointSize; + bool mUsesInstanceID; bool mUsesFragDepth; bool mUsesXor; - bool mUsesMod1; - bool mUsesMod2v; - bool mUsesMod2f; - bool mUsesMod3v; - bool mUsesMod3f; - bool mUsesMod4v; - bool mUsesMod4f; - bool mUsesFaceforward1; - bool mUsesFaceforward2; - bool mUsesFaceforward3; - bool mUsesFaceforward4; - bool mUsesAtan2_1; - bool mUsesAtan2_2; - bool mUsesAtan2_3; - bool mUsesAtan2_4; bool mUsesDiscardRewriting; bool mUsesNestedBreak; + bool mRequiresIEEEStrictCompiling; + int mNumRenderTargets; @@ -156,9 +181,41 @@ class OutputHLSL : public TIntermTraverser std::map mFlaggedStructMappedNames; std::map mFlaggedStructOriginalNames; - void makeFlaggedStructMaps(const std::vector &flaggedStructs); + // Some initializers use varyings, uniforms or attributes, thus we can't evaluate some variables + // at global static scope in HLSL. These variables depend on values which we retrieve from the + // shader input structure, which we set in the D3D main function. Instead, we can initialize + // these static globals after we initialize our other globals. + std::vector> mDeferredGlobalInitializers; + + struct HelperFunction + { + TString functionName; + TString functionDefinition; + + virtual ~HelperFunction() {} + }; + + // A list of all equality comparison functions. It's important to preserve the order at + // which we add the functions, since nested structures call each other recursively, and + // structure equality functions may need to call array equality functions and vice versa. + // The ownership of the pointers is maintained by the type-specific arrays. + std::vector mEqualityFunctions; + + struct StructEqualityFunction : public HelperFunction + { + const TStructure *structure; + }; + std::vector mStructEqualityFunctions; + + struct ArrayHelperFunction : public HelperFunction + { + TType type; + }; + std::vector mArrayEqualityFunctions; + + std::vector mArrayAssignmentFunctions; }; } -#endif // COMPILER_OUTPUTHLSL_H_ +#endif // COMPILER_TRANSLATOR_OUTPUTHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp index 37969b5468..7ad3f817ad 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp @@ -9,8 +9,9 @@ #include #include -#include "compiler/translator/glslang.h" #include "compiler/preprocessor/SourceLocation.h" +#include "compiler/translator/glslang.h" +#include "compiler/translator/ValidateSwitch.h" /////////////////////////////////////////////////////////////////////// // @@ -796,9 +797,24 @@ bool TParseContext::arrayErrorCheck(const TSourceLoc& line, const TString& ident bool sameScope = false; TSymbol* symbol = symbolTable.find(identifier, 0, &builtIn, &sameScope); if (symbol == 0 || !sameScope) { - if (reservedErrorCheck(line, identifier)) - return true; - + bool needsReservedErrorCheck = true; + + // gl_LastFragData may be redeclared with a new precision qualifier + if (identifier.compare(0, 15, "gl_LastFragData") == 0) { + if (type.arraySize == static_cast(symbolTable.findBuiltIn("gl_MaxDrawBuffers", shaderVersion))->getConstPointer()->getIConst()) { + if (TSymbol* builtInSymbol = symbolTable.findBuiltIn(identifier, shaderVersion)) { + needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension()); + } + } else { + error(line, "redeclaration of array with size != gl_MaxDrawBuffers", identifier.c_str()); + return true; + } + } + + if (needsReservedErrorCheck) + if (reservedErrorCheck(line, identifier)) + return true; + variable = new TVariable(&identifier, TType(type)); if (type.arraySize) @@ -976,6 +992,26 @@ bool TParseContext::layoutLocationErrorCheck(const TSourceLoc& location, const T return false; } +bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *aggregate) +{ + for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) + { + TQualifier qual = fnCandidate->getParam(i).type->getQualifier(); + if (qual == EvqOut || qual == EvqInOut) + { + TIntermTyped *node = (*(aggregate->getSequence()))[i]->getAsTyped(); + if (lValueErrorCheck(node->getLine(), "assign", node)) + { + error(node->getLine(), + "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); + recover(); + return true; + } + } + } + return false; +} + bool TParseContext::supportsExtension(const char* extension) { const TExtensionBehavior& extbehavior = extensionBehavior(); @@ -1062,14 +1098,14 @@ const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location, // // Return the function symbol if found, otherwise 0. // -const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int shaderVersion, bool *builtIn) +const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int inputShaderVersion, 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(), shaderVersion, builtIn); + const TSymbol* symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn); if (symbol == 0 || symbol->isFunction()) { - symbol = symbolTable.find(call->getMangledName(), shaderVersion, builtIn); + symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn); } if (symbol == 0) { @@ -1162,7 +1198,7 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id if (qualifier != EvqConst) { TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); - intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line); + intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line); if (intermNode == 0) { assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); return true; @@ -1375,7 +1411,7 @@ TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &inv recover(); return NULL; } - symbolTable.addInvariantVarying(*identifier); + symbolTable.addInvariantVarying(std::string(identifier->c_str())); const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); ASSERT(variable); const TType &type = variable->getType(); @@ -1605,7 +1641,7 @@ TFunction *TParseContext::addConstructorFunc(TPublicType publicType) // // 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) +TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line) { TIntermAggregate *aggregateArguments = arguments->getAsAggregate(); @@ -1633,13 +1669,21 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, const TType } // Turn the argument list itself into a constructor - TIntermTyped *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line); - TIntermTyped *constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type); + TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line); + TIntermTyped *constConstructor = foldConstConstructor(constructor, *type); if (constConstructor) { return constConstructor; } + // Structs should not be precision qualified, the individual members may be. + // Built-in types on the other hand should be precision qualified. + if (op != EOpConstructStruct) + { + constructor->setPrecisionFromChildren(); + type->setPrecision(constructor->getPrecision()); + } + return constructor; } @@ -2028,9 +2072,11 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co recover(); } - if (indexExpression->getQualifier() == EvqConst) + TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion(); + + if (indexExpression->getQualifier() == EvqConst && indexConstantUnion) { - int index = indexExpression->getAsConstantUnion()->getIConst(0); + int index = indexConstantUnion->getIConst(0); if (index < 0) { std::stringstream infoStream; @@ -2091,7 +2137,7 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co index = baseExpression->getType().getNominalSize() - 1; } - indexExpression->getAsConstantUnion()->getUnionArrayPointer()->setIConst(index); + indexConstantUnion->getUnionArrayPointer()->setIConst(index); indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location); } } @@ -2520,7 +2566,10 @@ TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSou TStructure* structure = new TStructure(structName, fieldList); TType* structureType = new TType(structure); + // Store a bool in the struct if we're at global scope, to allow us to + // skip the local struct scoping workaround in HLSL. structure->setUniqueId(TSymbolTable::nextUniqueId()); + structure->setAtGlobalScope(symbolTable.atGlobalLevel()); if (!structName->empty()) { @@ -2560,6 +2609,553 @@ TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSou return publicType; } +TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc) +{ + TBasicType switchType = init->getBasicType(); + if ((switchType != EbtInt && switchType != EbtUInt) || + init->isMatrix() || + init->isArray() || + init->isVector()) + { + error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch"); + recover(); + return nullptr; + } + + if (statementList) + { + if (!ValidateSwitch::validate(switchType, this, statementList, loc)) + { + recover(); + return nullptr; + } + } + + TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc); + if (node == nullptr) + { + error(loc, "erroneous switch statement", "switch"); + recover(); + return nullptr; + } + return node; +} + +TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc) +{ + if (mSwitchNestingLevel == 0) + { + error(loc, "case labels need to be inside switch statements", "case"); + recover(); + return nullptr; + } + if (condition == nullptr) + { + error(loc, "case label must have a condition", "case"); + recover(); + return nullptr; + } + if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) || + condition->isMatrix() || + condition->isArray() || + condition->isVector()) + { + error(condition->getLine(), "case label must be a scalar integer", "case"); + recover(); + } + TIntermConstantUnion *conditionConst = condition->getAsConstantUnion(); + if (conditionConst == nullptr) + { + error(condition->getLine(), "case label must be constant", "case"); + recover(); + } + TIntermCase *node = intermediate.addCase(condition, loc); + if (node == nullptr) + { + error(loc, "erroneous case statement", "case"); + recover(); + return nullptr; + } + return node; +} + +TIntermCase *TParseContext::addDefault(const TSourceLoc &loc) +{ + if (mSwitchNestingLevel == 0) + { + error(loc, "default labels need to be inside switch statements", "default"); + recover(); + return nullptr; + } + TIntermCase *node = intermediate.addCase(nullptr, loc); + if (node == nullptr) + { + error(loc, "erroneous default statement", "default"); + recover(); + return nullptr; + } + return node; +} + +TIntermTyped *TParseContext::createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc, + const TType *funcReturnType) +{ + if (child == nullptr) + { + return nullptr; + } + + switch (op) + { + case EOpLogicalNot: + if (child->getBasicType() != EbtBool || + child->isMatrix() || + child->isArray() || + child->isVector()) + { + return nullptr; + } + break; + case EOpBitwiseNot: + if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) || + child->isMatrix() || + child->isArray()) + { + return nullptr; + } + break; + case EOpPostIncrement: + case EOpPreIncrement: + case EOpPostDecrement: + case EOpPreDecrement: + case EOpNegative: + case EOpPositive: + if (child->getBasicType() == EbtStruct || + child->getBasicType() == EbtBool || + child->isArray()) + { + return nullptr; + } + // Operators for built-ins are already type checked against their prototype. + default: + break; + } + + return intermediate.addUnaryMath(op, child, loc, funcReturnType); +} + +TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) +{ + TIntermTyped *node = createUnaryMath(op, child, loc, nullptr); + if (node == nullptr) + { + unaryOpError(loc, GetOperatorString(op), child->getCompleteString()); + recover(); + return child; + } + return node; +} + +TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc) +{ + if (lValueErrorCheck(loc, GetOperatorString(op), child)) + recover(); + return addUnaryMath(op, child, loc); +} + +bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + if (left->isArray() || right->isArray()) + { + if (shaderVersion < 300) + { + error(loc, "Invalid operation for arrays", GetOperatorString(op)); + return false; + } + + if (left->isArray() != right->isArray()) + { + error(loc, "array / non-array mismatch", GetOperatorString(op)); + return false; + } + + switch (op) + { + case EOpEqual: + case EOpNotEqual: + case EOpAssign: + case EOpInitialize: + break; + default: + error(loc, "Invalid operation for arrays", GetOperatorString(op)); + return false; + } + if (left->getArraySize() != right->getArraySize()) + { + error(loc, "array size mismatch", GetOperatorString(op)); + return false; + } + } + + // Check ops which require integer / ivec parameters + bool isBitShift = false; + switch (op) + { + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + // Unsigned can be bit-shifted by signed and vice versa, but we need to + // check that the basic type is an integer type. + isBitShift = true; + if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType())) + { + return false; + } + break; + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + // It is enough to check the type of only one operand, since later it + // is checked that the operand types match. + if (!IsInteger(left->getBasicType())) + { + return false; + } + break; + default: + break; + } + + // GLSL ES 1.00 and 3.00 do not support implicit type casting. + // So the basic type should usually match. + if (!isBitShift && left->getBasicType() != right->getBasicType()) + { + return false; + } + + // Check that type sizes match exactly on ops that require that. + // Also check restrictions for structs that contain arrays or samplers. + switch(op) + { + case EOpAssign: + case EOpInitialize: + case EOpEqual: + case EOpNotEqual: + // ESSL 1.00 sections 5.7, 5.8, 5.9 + if (shaderVersion < 300 && left->getType().isStructureContainingArrays()) + { + error(loc, "undefined operation for structs containing arrays", GetOperatorString(op)); + return false; + } + // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7, + // we interpret the spec so that this extends to structs containing samplers, + // similarly to ESSL 1.00 spec. + if ((shaderVersion < 300 || op == EOpAssign || op == EOpInitialize) && + left->getType().isStructureContainingSamplers()) + { + error(loc, "undefined operation for structs containing samplers", GetOperatorString(op)); + return false; + } + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if ((left->getNominalSize() != right->getNominalSize()) || + (left->getSecondarySize() != right->getSecondarySize())) + { + return false; + } + default: + break; + } + + return true; +} + +TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + if (!binaryOpCommonCheck(op, left, right, loc)) + return nullptr; + + switch (op) + { + case EOpEqual: + case EOpNotEqual: + break; + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + ASSERT(!left->isArray() && !right->isArray()); + if (left->isMatrix() || left->isVector() || + left->getBasicType() == EbtStruct) + { + return nullptr; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + ASSERT(!left->isArray() && !right->isArray()); + if (left->getBasicType() != EbtBool || + left->isMatrix() || left->isVector()) + { + return nullptr; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + ASSERT(!left->isArray() && !right->isArray()); + if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) + { + return nullptr; + } + break; + case EOpIMod: + ASSERT(!left->isArray() && !right->isArray()); + // Note that this is only for the % operator, not for mod() + if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) + { + return nullptr; + } + break; + // Note that for bitwise ops, type checking is done in promote() to + // share code between ops and compound assignment + default: + break; + } + + return intermediate.addBinaryMath(op, left, right, loc); +} + +TIntermTyped *TParseContext::addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); + if (node == 0) + { + binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString()); + recover(); + return left; + } + return node; +} + +TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); + if (node == 0) + { + binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString()); + recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), loc); + } + return node; +} + +TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + if (binaryOpCommonCheck(op, left, right, loc)) + { + return intermediate.addAssign(op, left, right, loc); + } + return nullptr; +} + +TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + TIntermTyped *node = createAssign(op, left, right, loc); + if (node == nullptr) + { + assignError(loc, "assign", left->getCompleteString(), right->getCompleteString()); + recover(); + return left; + } + return node; +} + +TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) +{ + switch (op) + { + case EOpContinue: + if (mLoopNestingLevel <= 0) + { + error(loc, "continue statement only allowed in loops", ""); + recover(); + } + break; + case EOpBreak: + if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0) + { + error(loc, "break statement only allowed in loops and switch statements", ""); + recover(); + } + break; + case EOpReturn: + if (currentFunctionType->getBasicType() != EbtVoid) + { + error(loc, "non-void function must return a value", "return"); + recover(); + } + break; + default: + // No checks for discard + break; + } + return intermediate.addBranch(op, loc); +} + +TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc) +{ + ASSERT(op == EOpReturn); + mFunctionReturnsValue = true; + if (currentFunctionType->getBasicType() == EbtVoid) + { + error(loc, "void function cannot return a value", "return"); + recover(); + } + else if (*currentFunctionType != returnValue->getType()) + { + error(loc, "function return is not matching type:", "return"); + recover(); + } + return intermediate.addBranch(op, returnValue, loc); +} + +TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node, + const TSourceLoc &loc, bool *fatalError) +{ + *fatalError = false; + TOperator op = fnCall->getBuiltInOp(); + TIntermTyped *callNode = nullptr; + + if (op != EOpNull) + { + // + // Then this should be a constructor. + // Don't go through the symbol table for constructors. + // Their parameters will be verified algorithmically. + // + TType type(EbtVoid, EbpUndefined); // use this to get the type back + if (!constructorErrorCheck(loc, node, *fnCall, op, &type)) + { + // + // It's a constructor, of type 'type'. + // + callNode = addConstructor(node, &type, op, fnCall, loc); + } + + if (callNode == nullptr) + { + recover(); + callNode = intermediate.setAggregateOperator(nullptr, op, loc); + } + callNode->setType(type); + } + else + { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction* fnCandidate; + bool builtIn; + fnCandidate = findFunction(loc, fnCall, shaderVersion, &builtIn); + if (fnCandidate) + { + // + // A declared function. + // + if (builtIn && !fnCandidate->getExtension().empty() && + extensionErrorCheck(loc, fnCandidate->getExtension())) + { + recover(); + } + op = fnCandidate->getBuiltInOp(); + if (builtIn && op != EOpNull) + { + // + // A function call mapped to a built-in operation. + // + if (fnCandidate->getParamCount() == 1) + { + // + // Treat it like a built-in unary operator. + // + callNode = createUnaryMath(op, node->getAsTyped(), loc, &fnCandidate->getReturnType()); + if (callNode == nullptr) + { + std::stringstream extraInfoStream; + extraInfoStream << "built in unary operator function. Type: " + << static_cast(node)->getCompleteString(); + std::string extraInfo = extraInfoStream.str(); + error(node->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); + *fatalError = true; + return nullptr; + } + } + else + { + TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, op, loc); + aggregate->setType(fnCandidate->getReturnType()); + aggregate->setPrecisionFromChildren(); + callNode = aggregate; + + // Some built-in functions have out parameters too. + functionCallLValueErrorCheck(fnCandidate, aggregate); + } + } + else + { + // This is a real function call + + TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, EOpFunctionCall, loc); + aggregate->setType(fnCandidate->getReturnType()); + + // this is how we know whether the given function is a builtIn function or a user defined function + // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also + // if builtIn == true, it's definitely a builtIn function with EOpNull + if (!builtIn) + aggregate->setUserDefined(); + aggregate->setName(fnCandidate->getMangledName()); + + // This needs to happen after the name is set + if (builtIn) + aggregate->setBuiltInFunctionPrecision(); + + callNode = aggregate; + + functionCallLValueErrorCheck(fnCandidate, aggregate); + } + } + else + { + // error message was put out by findFunction() + // Put on a dummy node for error recovery + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + callNode = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), loc); + recover(); + } + } + delete fnCall; + return callNode; +} + + // // 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 414c475cbb..b6a0f4a637 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.h +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.h @@ -3,8 +3,8 @@ // 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_ +#ifndef COMPILER_TRANSLATOR_PARSECONTEXT_H_ +#define COMPILER_TRANSLATOR_PARSECONTEXT_H_ #include "compiler/translator/Compiler.h" #include "compiler/translator/Diagnostics.h" @@ -25,24 +25,25 @@ struct TMatrixFields { // they can be passed to the parser without needing a global. // struct TParseContext { - TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, sh::GLenum 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, TInfoSink& is, bool debugShaderPrecisionSupported) : intermediate(interm), symbolTable(symt), shaderType(type), shaderSpec(spec), compileOptions(options), - sourcePath(sourcePath), treeRoot(0), - loopNestingLevel(0), + mLoopNestingLevel(0), structNestingLevel(0), + mSwitchNestingLevel(0), currentFunctionType(NULL), - functionReturnsValue(false), + mFunctionReturnsValue(false), checksPrecisionErrors(checksPrecErrors), + fragmentPrecisionHigh(false), defaultMatrixPacking(EmpColumnMajor), defaultBlockStorage(EbsShared), diagnostics(is), shaderVersion(100), - directiveHandler(ext, diagnostics, shaderVersion), + directiveHandler(ext, diagnostics, shaderVersion, debugShaderPrecisionSupported), preprocessor(&diagnostics, &directiveHandler), scanner(NULL) { } TIntermediate& intermediate; // to hold and build a parse tree @@ -51,12 +52,12 @@ struct TParseContext { 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 - int loopNestingLevel; // 0 if outside all loops + int mLoopNestingLevel; // 0 if outside all loops int structNestingLevel; // incremented while parsing a struct declaration + int mSwitchNestingLevel; // 0 if outside all switch statements const TType* currentFunctionType; // the return type of the function that's currently being parsed - bool functionReturnsValue; // true if a non-void function has a return + bool mFunctionReturnsValue; // 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; @@ -110,6 +111,7 @@ struct TParseContext { 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); + bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *); const TPragma& pragma() const { return directiveHandler.pragma(); } const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); } @@ -120,7 +122,7 @@ struct TParseContext { bool containsSampler(TType& type); bool areAllChildConst(TIntermAggregate* aggrNode); - const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, int shaderVersion, bool *builtIn = 0); + const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, int inputShaderVersion, bool *builtIn = 0); bool executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType, TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0); @@ -136,7 +138,7 @@ struct TParseContext { 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* addConstructor(TIntermNode*, TType*, TOperator, TFunction*, const TSourceLoc&); TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type); TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&); TIntermTyped* addConstMatrixNode(int , TIntermTyped*, const TSourceLoc&); @@ -164,9 +166,42 @@ struct TParseContext { void exitStructDeclaration(); bool structNestingErrorCheck(const TSourceLoc& line, const TField& field); + + TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc); + TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc); + TIntermCase *addDefault(const TSourceLoc &loc); + + TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &); + TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &); + TIntermTyped *addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &); + TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &); + TIntermTyped *addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc); + + TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc); + TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc); + + TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node, + const TSourceLoc &loc, bool *fatalError); + + private: + TIntermTyped *addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc); + TIntermTyped *createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc); + // The funcReturnType parameter is expected to be non-null when the operation is a built-in function. + // It is expected to be null for other unary operators. + TIntermTyped *createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc, + const TType *funcReturnType); + + // Return true if the checks pass + bool binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc); }; int PaParseStrings(size_t count, const char* const string[], const int length[], TParseContext* context); -#endif // _PARSER_HELPER_INCLUDED_ +#endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h index edd249c4d3..6cd8d30114 100644 --- a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h +++ b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _POOLALLOC_INCLUDED_ -#define _POOLALLOC_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_POOLALLOC_H_ +#define COMPILER_TRANSLATOR_POOLALLOC_H_ #ifdef _DEBUG #define GUARD_BLOCKS // define to enable guard block sanity checking @@ -297,4 +297,4 @@ protected: TPoolAllocator* allocator; }; -#endif // _POOLALLOC_INCLUDED_ +#endif // COMPILER_TRANSLATOR_POOLALLOC_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Pragma.h b/src/3rdparty/angle/src/compiler/translator/Pragma.h index 4a930a2962..57b1134970 100644 --- a/src/3rdparty/angle/src/compiler/translator/Pragma.h +++ b/src/3rdparty/angle/src/compiler/translator/Pragma.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PRAGMA_H_ -#define COMPILER_PRAGMA_H_ +#ifndef COMPILER_TRANSLATOR_PRAGMA_H_ +#define COMPILER_TRANSLATOR_PRAGMA_H_ struct TPragma { @@ -18,12 +18,15 @@ struct TPragma // By default optimization is turned on and debug is turned off. - TPragma() : optimize(true), debug(false) { } - TPragma(bool o, bool d) : optimize(o), debug(d) { } + // Precision emulation is turned on by default, but has no effect unless + // the extension is enabled. + TPragma() : optimize(true), debug(false), debugShaderPrecision(true) { } + TPragma(bool o, bool d) : optimize(o), debug(d), debugShaderPrecision(true) { } bool optimize; bool debug; + bool debugShaderPrecision; STDGL stdgl; }; -#endif // COMPILER_PRAGMA_H_ +#endif // COMPILER_TRANSLATOR_PRAGMA_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp index 1f6fb75821..3d950aab5a 100644 --- a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp +++ b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp @@ -49,7 +49,7 @@ void TAliveTraverser::visitSymbol(TIntermSymbol* node) found = true; } -bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node) +bool TAliveTraverser::visitSelection(Visit, TIntermSelection*) { if (wasFound()) return false; diff --git a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h index 872a06f721..3e4f18012a 100644 --- a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h +++ b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h @@ -4,4 +4,9 @@ // found in the LICENSE file. // +#ifndef COMPILER_TRANSLATOR_QUALIFIERALIVE_H_ +#define COMPILER_TRANSLATOR_QUALIFIERALIVE_H_ + bool QualifierWritten(TIntermNode* root, TQualifier); + +#endif // COMPILER_TRANSLATOR_QUALIFIERALIVE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h index ac87600347..2acd68be34 100644 --- a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h +++ b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATOR_REGENERATE_STRUCT_NAMES_H_ -#define COMPILER_TRANSLATOR_REGENERATE_STRUCT_NAMES_H_ +#ifndef COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_ +#define COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_ #include "compiler/translator/Intermediate.h" #include "compiler/translator/SymbolTable.h" @@ -37,4 +37,4 @@ class RegenerateStructNames : public TIntermTraverser std::set mDeclaredGlobalStructs; }; -#endif // COMPILER_TRANSLATOR_REGENERATE_STRUCT_NAMES_H_ +#endif // COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp new file mode 100644 index 0000000000..b278b53436 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp @@ -0,0 +1,157 @@ +// +// Copyright (c) 2002-2015 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/RemoveSwitchFallThrough.h" + +TIntermAggregate *RemoveSwitchFallThrough::removeFallThrough(TIntermAggregate *statementList) +{ + RemoveSwitchFallThrough rm(statementList); + ASSERT(statementList); + statementList->traverse(&rm); + bool lastStatementWasBreak = rm.mLastStatementWasBreak; + rm.mLastStatementWasBreak = true; + rm.handlePreviousCase(); + if (!lastStatementWasBreak) + { + TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr); + rm.mStatementListOut->getSequence()->push_back(finalBreak); + } + return rm.mStatementListOut; +} + +RemoveSwitchFallThrough::RemoveSwitchFallThrough(TIntermAggregate *statementList) + : TIntermTraverser(true, false, false), + mStatementList(statementList), + mLastStatementWasBreak(false), + mPreviousCase(nullptr) +{ + mStatementListOut = new TIntermAggregate(); + mStatementListOut->setOp(EOpSequence); +} + +void RemoveSwitchFallThrough::visitSymbol(TIntermSymbol *node) +{ + // Note that this assumes that switch statements which don't begin by a case statement + // have already been weeded out in validation. + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; +} + +void RemoveSwitchFallThrough::visitConstantUnion(TIntermConstantUnion *node) +{ + // Conditions of case labels are not traversed, so this is some other constant + // Could be just a statement like "0;" + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; +} + +bool RemoveSwitchFallThrough::visitBinary(Visit, TIntermBinary *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThrough::visitSelection(Visit, TIntermSelection *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThrough::visitSwitch(Visit, TIntermSwitch *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + // Don't go into nested switch statements + return false; +} + +void RemoveSwitchFallThrough::outputSequence(TIntermSequence *sequence, size_t startIndex) +{ + for (size_t i = startIndex; i < sequence->size(); ++i) + { + mStatementListOut->getSequence()->push_back(sequence->at(i)); + } +} + +void RemoveSwitchFallThrough::handlePreviousCase() +{ + if (mPreviousCase) + mCasesSharingBreak.push_back(mPreviousCase); + if (mLastStatementWasBreak) + { + bool labelsWithNoStatements = true; + for (size_t i = 0; i < mCasesSharingBreak.size(); ++i) + { + if (mCasesSharingBreak.at(i)->getSequence()->size() > 1) + { + labelsWithNoStatements = false; + } + if (labelsWithNoStatements) + { + // Fall-through is allowed in case the label has no statements. + outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0); + } + else + { + // Include all the statements that this case can fall through under the same label. + for (size_t j = i; j < mCasesSharingBreak.size(); ++j) + { + size_t startIndex = j > i ? 1 : 0; // Add the label only from the first sequence. + outputSequence(mCasesSharingBreak.at(j)->getSequence(), startIndex); + + } + } + } + mCasesSharingBreak.clear(); + } + mLastStatementWasBreak = false; + mPreviousCase = nullptr; +} + +bool RemoveSwitchFallThrough::visitCase(Visit, TIntermCase *node) +{ + handlePreviousCase(); + mPreviousCase = new TIntermAggregate(); + mPreviousCase->setOp(EOpSequence); + mPreviousCase->getSequence()->push_back(node); + // Don't traverse the condition of the case statement + return false; +} + +bool RemoveSwitchFallThrough::visitAggregate(Visit, TIntermAggregate *node) +{ + if (node != mStatementList) + { + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; + } + return true; +} + +bool RemoveSwitchFallThrough::visitLoop(Visit, TIntermLoop *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThrough::visitBranch(Visit, TIntermBranch *node) +{ + mPreviousCase->getSequence()->push_back(node); + // TODO: Verify that accepting return or continue statements here doesn't cause problems. + mLastStatementWasBreak = true; + return false; +} diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h new file mode 100644 index 0000000000..db8699327c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h @@ -0,0 +1,43 @@ +// +// Copyright (c) 2002-2015 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_REMOVESWITCHFALLTHROUGH_H_ +#define COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_ + +#include "compiler/translator/IntermNode.h" + +class RemoveSwitchFallThrough : public TIntermTraverser +{ + public: + // When given a statementList from a switch AST node, return an updated + // statementList that has fall-through removed. + static TIntermAggregate *removeFallThrough(TIntermAggregate *statementList); + + private: + RemoveSwitchFallThrough(TIntermAggregate *statementList); + + void visitSymbol(TIntermSymbol *node) override; + void visitConstantUnion(TIntermConstantUnion *node) override; + bool visitBinary(Visit, TIntermBinary *node) override; + bool visitUnary(Visit, TIntermUnary *node) override; + bool visitSelection(Visit visit, TIntermSelection *node) override; + bool visitSwitch(Visit, TIntermSwitch *node) override; + bool visitCase(Visit, TIntermCase *node) override; + bool visitAggregate(Visit, TIntermAggregate *node) override; + bool visitLoop(Visit, TIntermLoop *node) override; + bool visitBranch(Visit, TIntermBranch *node) override; + + void outputSequence(TIntermSequence *sequence, size_t startIndex); + void handlePreviousCase(); + + TIntermAggregate *mStatementList; + TIntermAggregate *mStatementListOut; + bool mLastStatementWasBreak; + TIntermAggregate *mPreviousCase; + std::vector mCasesSharingBreak; +}; + +#endif // COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp deleted file mode 100644 index 0cf6910aa2..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp +++ /dev/null @@ -1,29 +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/IntermNode.h" -#include "compiler/translator/RemoveTree.h" - -// -// Code to delete the intermediate tree. -// -void RemoveAllTreeNodes(TIntermNode* root) -{ - std::queue nodeQueue; - - nodeQueue.push(root); - - while (!nodeQueue.empty()) - { - TIntermNode *node = nodeQueue.front(); - nodeQueue.pop(); - - node->enqueueChildren(&nodeQueue); - - delete node; - } -} - diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveTree.h b/src/3rdparty/angle/src/compiler/translator/RemoveTree.h deleted file mode 100644 index 97a821679c..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/RemoveTree.h +++ /dev/null @@ -1,7 +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. -// - -void RemoveAllTreeNodes(TIntermNode*); diff --git a/src/3rdparty/angle/src/compiler/translator/RenameFunction.h b/src/3rdparty/angle/src/compiler/translator/RenameFunction.h index d43e6ef7be..868e5d566b 100644 --- a/src/3rdparty/angle/src/compiler/translator/RenameFunction.h +++ b/src/3rdparty/angle/src/compiler/translator/RenameFunction.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_RENAME_FUNCTION -#define COMPILER_RENAME_FUNCTION +#ifndef COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ +#define COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ #include "compiler/translator/IntermNode.h" @@ -33,4 +33,4 @@ private: const TString mNewFunctionName; }; -#endif // COMPILER_RENAME_FUNCTION +#endif // COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h index d87baea0fe..5527d27f83 100644 --- a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h +++ b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h @@ -7,8 +7,8 @@ // all if-else blocks to if-if blocks. // -#ifndef COMPILER_REWRITE_ELSE_BLOCKS_H_ -#define COMPILER_REWRITE_ELSE_BLOCKS_H_ +#ifndef COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ +#define COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ #include "compiler/translator/IntermNode.h" @@ -19,4 +19,4 @@ void RewriteElseBlocks(TIntermNode *node); } -#endif // COMPILER_REWRITE_ELSE_BLOCKS_H_ +#endif // COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h index 7c6d09c1bb..0726ed4c64 100644 --- a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h +++ b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h @@ -4,8 +4,8 @@ // 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_ +#ifndef COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ +#define COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ #include "compiler/translator/IntermNode.h" @@ -44,4 +44,4 @@ class ScalarizeVecAndMatConstructorArgs : public TIntermTraverser bool mFragmentPrecisionHigh; }; -#endif // COMPILER_TRANSLATOR_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS_H_ +#endif // COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp index f78c84e370..fb7a6cdb9b 100644 --- a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp @@ -9,7 +9,6 @@ #include "compiler/translator/SearchSymbol.h" #include "compiler/translator/InfoSink.h" -#include "compiler/translator/OutputHLSL.h" namespace sh { diff --git a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h index 029ac30b9a..36d5191058 100644 --- a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h +++ b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h @@ -6,8 +6,8 @@ // SearchSymbol is an AST traverser to detect the use of a given symbol name // -#ifndef COMPILER_SEARCHSYMBOL_H_ -#define COMPILER_SEARCHSYMBOL_H_ +#ifndef COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ +#define COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ #include "compiler/translator/IntermNode.h" #include "compiler/translator/ParseContext.h" @@ -30,4 +30,4 @@ class SearchSymbol : public TIntermTraverser }; } -#endif // COMPILER_SEARCHSYMBOL_H_ +#endif // COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp index 0d6a1d64cf..b8040da7f9 100644 --- a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp @@ -14,7 +14,9 @@ #include "compiler/translator/Compiler.h" #include "compiler/translator/InitializeDll.h" #include "compiler/translator/length_limits.h" +#ifdef ANGLE_ENABLE_HLSL #include "compiler/translator/TranslatorHLSL.h" +#endif // ANGLE_ENABLE_HLSL #include "compiler/translator/VariablePacker.h" #include "angle_gl.h" @@ -92,6 +94,7 @@ TCompiler *GetCompilerFromHandle(ShHandle handle) return base->getAsCompiler(); } +#ifdef ANGLE_ENABLE_HLSL TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle) { if (!handle) @@ -99,6 +102,7 @@ TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle) TShHandleBase *base = static_cast(handle); return base->getAsTranslatorHLSL(); } +#endif // ANGLE_ENABLE_HLSL } // namespace anonymous @@ -153,6 +157,10 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) resources->EXT_draw_buffers = 0; resources->EXT_frag_depth = 0; resources->EXT_shader_texture_lod = 0; + resources->WEBGL_debug_shader_precision = 0; + resources->EXT_shader_framebuffer_fetch = 0; + resources->NV_shader_framebuffer_fetch = 0; + resources->ARM_shader_framebuffer_fetch = 0; resources->NV_draw_buffers = 0; @@ -323,6 +331,7 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle, const std::string &interfaceBlockName, unsigned int *indexOut) { +#ifdef ANGLE_ENABLE_HLSL ASSERT(indexOut); TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); @@ -335,12 +344,16 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle, *indexOut = translator->getInterfaceBlockRegister(interfaceBlockName); return true; +#else + return false; +#endif // ANGLE_ENABLE_HLSL } bool ShGetUniformRegister(const ShHandle handle, const std::string &uniformName, unsigned int *indexOut) { +#ifdef ANGLE_ENABLE_HLSL ASSERT(indexOut); TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); ASSERT(translator); @@ -352,4 +365,7 @@ bool ShGetUniformRegister(const ShHandle handle, *indexOut = translator->getUniformRegister(uniformName); return true; +#else + return false; +#endif // ANGLE_ENABLE_HLSL } diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp index 3098a7f0c9..0dbbc9e7f6 100644 --- a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp @@ -14,6 +14,23 @@ namespace sh { +namespace +{ + +InterpolationType GetNonAuxiliaryInterpolationType(InterpolationType interpolation) +{ + return (interpolation == INTERPOLATION_CENTROID ? INTERPOLATION_SMOOTH : interpolation); +} + +} +// The ES 3.0 spec is not clear on this point, but the ES 3.1 spec, and discussion +// on Khronos.org, clarifies that a smooth/flat mismatch produces a link error, +// but auxiliary qualifier mismatch (centroid) does not. +bool InterpolationTypesMatch(InterpolationType a, InterpolationType b) +{ + return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b)); +} + ShaderVariable::ShaderVariable() : type(0), precision(0), @@ -86,7 +103,6 @@ bool ShaderVariable::findInfoByMappedName( // 2) the top variable is an array; // 3) otherwise. size_t pos = mappedFullName.find_first_of(".["); - std::string topName; if (pos == std::string::npos) { diff --git a/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp new file mode 100644 index 0000000000..ac5eb67070 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2002-2015 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/SimplifyArrayAssignment.h" + +bool SimplifyArrayAssignment::visitBinary(Visit visit, TIntermBinary *node) +{ + switch (node->getOp()) + { + case EOpAssign: + { + TIntermNode *parent = getParentNode(); + if (node->getLeft()->isArray() && parent != nullptr) + { + TIntermAggregate *parentAgg = parent->getAsAggregate(); + if (parentAgg != nullptr && parentAgg->getOp() == EOpSequence) + { + // This case is fine, the result of the assignment is not used. + break; + } + + // The result of the assignment needs to be stored into a temporary variable, + // the assignment needs to be replaced with a reference to the temporary variable, + // and the temporary variable needs to finally be assigned to the target variable. + + // This also needs to interact correctly with unfolding short circuiting operators. + UNIMPLEMENTED(); + } + } + break; + default: + break; + } + return true; +} diff --git a/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h new file mode 100644 index 0000000000..247eb88d72 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2002-2015 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. +// +// SimplifyArrayAssignment is an AST traverser to replace statements where +// the return value of array assignment is used with statements where +// the return value of array assignment is not used. +// + +#ifndef COMPILER_TRANSLATOR_SIMPLIFYARRAYASSIGNMENT_H_ +#define COMPILER_TRANSLATOR_SIMPLIFYARRAYASSIGNMENT_H_ + +#include "common/angleutils.h" +#include "compiler/translator/IntermNode.h" + +class SimplifyArrayAssignment : public TIntermTraverser +{ + public: + SimplifyArrayAssignment() { } + + virtual bool visitBinary(Visit visit, TIntermBinary *node); +}; + +#endif // COMPILER_TRANSLATOR_SIMPLIFYARRAYASSIGNMENT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp index 48929affe6..fd1a29c1cd 100644 --- a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp @@ -21,9 +21,23 @@ Std140PaddingHelper::Std140PaddingHelper(const std::map &structEle unsigned *uniqueCounter) : mPaddingCounter(uniqueCounter), mElementIndex(0), - mStructElementIndexes(structElementIndexes) + mStructElementIndexes(&structElementIndexes) {} +Std140PaddingHelper::Std140PaddingHelper(const Std140PaddingHelper &other) + : mPaddingCounter(other.mPaddingCounter), + mElementIndex(other.mElementIndex), + mStructElementIndexes(other.mStructElementIndexes) +{} + +Std140PaddingHelper &Std140PaddingHelper::operator=(const Std140PaddingHelper &other) +{ + mPaddingCounter = other.mPaddingCounter; + mElementIndex = other.mElementIndex; + mStructElementIndexes = other.mStructElementIndexes; + return *this; +} + TString Std140PaddingHelper::next() { unsigned value = (*mPaddingCounter)++; @@ -107,7 +121,7 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRo { const TString &structName = QualifiedStructNameString(*structure, useHLSLRowMajorPacking, true); - numComponents = mStructElementIndexes.find(structName)->second; + numComponents = mStructElementIndexes->find(structName)->second; if (numComponents == 0) { @@ -274,9 +288,9 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) { - const TType &type = ctorParameters[parameter]; + const TType ¶mType = ctorParameters[parameter]; - constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type); + constructor += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType); if (parameter < ctorParameters.size() - 1) { diff --git a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h index ed002fef30..cffe2a41ae 100644 --- a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h @@ -7,8 +7,8 @@ // Interfaces of methods for HLSL translation of GLSL structures. // -#ifndef TRANSLATOR_STRUCTUREHLSL_H_ -#define TRANSLATOR_STRUCTUREHLSL_H_ +#ifndef COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ +#define COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ #include "compiler/translator/Common.h" #include "compiler/translator/IntermNode.h" @@ -27,7 +27,9 @@ class Std140PaddingHelper { public: explicit Std140PaddingHelper(const std::map &structElementIndexes, - unsigned *uniqueCounter); + unsigned int *uniqueCounter); + Std140PaddingHelper(const Std140PaddingHelper &other); + Std140PaddingHelper &operator=(const Std140PaddingHelper &other); int elementIndex() const { return mElementIndex; } int prePadding(const TType &type); @@ -39,10 +41,10 @@ class Std140PaddingHelper unsigned *mPaddingCounter; int mElementIndex; - const std::map &mStructElementIndexes; + const std::map *mStructElementIndexes; }; -class StructureHLSL +class StructureHLSL : angle::NonCopyable { public: StructureHLSL(); @@ -76,4 +78,4 @@ class StructureHLSL } -#endif // COMPILER_STRUCTUREHLSL_H_ +#endif // COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp index 028da21151..0eb663f018 100644 --- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp @@ -48,6 +48,16 @@ bool TSymbolTableLevel::insert(TSymbol *symbol) return result.second; } +bool TSymbolTableLevel::insertUnmangled(TFunction *function) +{ + function->setUniqueId(TSymbolTable::nextUniqueId()); + + // returning true means symbol was added to the table + tInsertResult result = level.insert(tLevelPair(function->getName(), function)); + + return result.second; +} + TSymbol *TSymbolTableLevel::find(const TString &name) const { tLevel::const_iterator it = level.find(name); @@ -57,47 +67,6 @@ TSymbol *TSymbolTableLevel::find(const TString &name) const return (*it).second; } -// -// 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) -{ - 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); - } - } -} - -// -// 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); - } -} - -TSymbol::TSymbol(const TSymbol ©Of) -{ - name = NewPoolTString(copyOf.name->c_str()); - uniqueId = copyOf.uniqueId; -} - TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, bool *builtIn, bool *sameScope) const { @@ -148,68 +117,149 @@ TSymbolTable::~TSymbolTable() pop(); } -void TSymbolTable::insertBuiltIn( - ESymbolLevel level, TType *rvalue, const char *name, - TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5) +bool IsGenType(const TType *type) +{ + if (type) + { + TBasicType basicType = type->getBasicType(); + return basicType == EbtGenType || basicType == EbtGenIType || basicType == EbtGenUType || basicType == EbtGenBType; + } + + return false; +} + +bool IsVecType(const TType *type) +{ + if (type) + { + TBasicType basicType = type->getBasicType(); + return basicType == EbtVec || basicType == EbtIVec || basicType == EbtUVec || basicType == EbtBVec; + } + + return false; +} + +TType *SpecificType(TType *type, int size) +{ + ASSERT(size >= 1 && size <= 4); + + if (!type) + { + return nullptr; + } + + ASSERT(!IsVecType(type)); + + switch(type->getBasicType()) + { + case EbtGenType: return new TType(EbtFloat, size); + case EbtGenIType: return new TType(EbtInt, size); + case EbtGenUType: return new TType(EbtUInt, size); + case EbtGenBType: return new TType(EbtBool, size); + default: return type; + } +} + +TType *VectorType(TType *type, int size) +{ + ASSERT(size >= 2 && size <= 4); + + if (!type) + { + return nullptr; + } + + ASSERT(!IsGenType(type)); + + switch(type->getBasicType()) + { + case EbtVec: return new TType(EbtFloat, size); + case EbtIVec: return new TType(EbtInt, size); + case EbtUVec: return new TType(EbtUInt, size); + case EbtBVec: return new TType(EbtBool, size); + default: return type; + } +} + +void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5) { 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; + 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); } - if (ptype1->getBasicType() == EbtGSampler3D) + else 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; + 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); } - if (ptype1->getBasicType() == EbtGSamplerCube) + else 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; + 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); } - if (ptype1->getBasicType() == EbtGSampler2DArray) + else 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; + 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); + } + else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3)) + { + ASSERT(!ptype4 && !ptype5); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 1), name, SpecificType(ptype1, 1), SpecificType(ptype2, 1), SpecificType(ptype3, 1)); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 2), name, SpecificType(ptype1, 2), SpecificType(ptype2, 2), SpecificType(ptype3, 2)); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 3), name, SpecificType(ptype1, 3), SpecificType(ptype2, 3), SpecificType(ptype3, 3)); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 4), name, SpecificType(ptype1, 4), SpecificType(ptype2, 4), SpecificType(ptype3, 4)); + } + else if (IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3)) + { + ASSERT(!ptype4 && !ptype5); + insertBuiltIn(level, op, ext, VectorType(rvalue, 2), name, VectorType(ptype1, 2), VectorType(ptype2, 2), VectorType(ptype3, 2)); + insertBuiltIn(level, op, ext, VectorType(rvalue, 3), name, VectorType(ptype1, 3), VectorType(ptype2, 3), VectorType(ptype3, 3)); + insertBuiltIn(level, op, ext, VectorType(rvalue, 4), name, VectorType(ptype1, 4), VectorType(ptype2, 4), VectorType(ptype3, 4)); } + else + { + TFunction *function = new TFunction(NewPoolTString(name), *rvalue, op, ext); - TFunction *function = new TFunction(NewPoolTString(name), *rvalue); + TParameter param1 = {0, ptype1}; + function->addParameter(param1); - TType *types[] = {ptype1, ptype2, ptype3, ptype4, ptype5}; - for (size_t ii = 0; ii < sizeof(types) / sizeof(types[0]); ++ii) - { - if (types[ii]) + if (ptype2) { - TParameter param = {NULL, types[ii]}; - function->addParameter(param); + TParameter param2 = {0, ptype2}; + function->addParameter(param2); } - } - insert(level, function); + if (ptype3) + { + TParameter param3 = {0, ptype3}; + function->addParameter(param3); + } + + if (ptype4) + { + TParameter param4 = {0, ptype4}; + function->addParameter(param4); + } + + if (ptype5) + { + TParameter param5 = {0, ptype5}; + function->addParameter(param5); + } + + insert(level, function); + } } TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h index 9cd74218dc..dfc65cb957 100644 --- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h +++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _SYMBOL_TABLE_INCLUDED_ -#define _SYMBOL_TABLE_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_H_ +#define COMPILER_TRANSLATOR_SYMBOLTABLE_H_ // // Symbol table for parsing. Has these design characteristics: @@ -38,7 +38,7 @@ #include "compiler/translator/IntermNode.h" // Symbol base class. (Can build functions or variables out of these...) -class TSymbol +class TSymbol : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE(); @@ -86,8 +86,6 @@ class TSymbol } private: - DISALLOW_COPY_AND_ASSIGN(TSymbol); - int uniqueId; // For real comparing during code generation const TString *name; TString extension; @@ -158,8 +156,6 @@ class TVariable : public TSymbol } private: - DISALLOW_COPY_AND_ASSIGN(TVariable); - TType type; bool userType; // we are assuming that Pool Allocator will free the memory @@ -186,13 +182,14 @@ class TFunction : public TSymbol defined(false) { } - TFunction(const TString *name, const TType &retType, TOperator tOp = EOpNull) + TFunction(const TString *name, const TType &retType, TOperator tOp = EOpNull, const char *ext = "") : TSymbol(name), returnType(retType), mangledName(TFunction::mangleName(*name)), op(tOp), defined(false) { + relateToExtension(ext); } virtual ~TFunction(); virtual bool isFunction() const @@ -224,10 +221,6 @@ class TFunction : public TSymbol return returnType; } - void relateToOperator(TOperator o) - { - op = o; - } TOperator getBuiltInOp() const { return op; @@ -252,8 +245,6 @@ class TFunction : public TSymbol } private: - DISALLOW_COPY_AND_ASSIGN(TFunction); - typedef TVector TParamList; TParamList parameters; TType returnType; @@ -291,10 +282,10 @@ class TSymbolTableLevel bool insert(TSymbol *symbol); - TSymbol *find(const TString &name) const; + // Insert a function using its unmangled name as the key. + bool insertUnmangled(TFunction *function); - void relateToOperator(const char *name, TOperator op); - void relateToExtension(const char *name, const TString &ext); + TSymbol *find(const TString &name) const; protected: tLevel level; @@ -310,7 +301,7 @@ const int ESSL3_BUILTINS = 2; const int LAST_BUILTIN_LEVEL = ESSL3_BUILTINS; const int GLOBAL_LEVEL = 3; -class TSymbolTable +class TSymbolTable : angle::NonCopyable { public: TSymbolTable() @@ -363,6 +354,12 @@ class TSymbolTable return table[level]->insert(symbol); } + bool insert(ESymbolLevel level, const char *ext, TSymbol *symbol) + { + symbol->relateToExtension(ext); + return table[level]->insert(symbol); + } + bool insertConstInt(ESymbolLevel level, const char *name, int value) { TVariable *constant = new TVariable( @@ -371,9 +368,26 @@ class TSymbolTable return insert(level, constant); } + void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0); + void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name, - TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, - TType *ptype4 = 0, TType *ptype5 = 0); + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0) + { + insertBuiltIn(level, EOpNull, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); + } + + void insertBuiltIn(ESymbolLevel level, const char *ext, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0) + { + insertBuiltIn(level, EOpNull, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); + } + + void insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0) + { + insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); + } TSymbol *find(const TString &name, int shaderVersion, bool *builtIn = NULL, bool *sameScope = NULL) const; @@ -385,14 +399,6 @@ class TSymbolTable return table[currentLevel() - 1]; } - void relateToOperator(ESymbolLevel level, const char *name, TOperator op) - { - table[level]->relateToOperator(name, op); - } - 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) @@ -413,7 +419,7 @@ class TSymbolTable // This records invariant varyings declared through // "invariant varying_name;". - void addInvariantVarying(const TString &originalName) + void addInvariantVarying(const std::string &originalName) { mInvariantVaryings.insert(originalName); } @@ -421,7 +427,7 @@ class TSymbolTable // if it is set as invariant during the varying variable // declaration - this piece of information is stored in the // variable's type, not here. - bool isVaryingInvariant(const TString &originalName) const + bool isVaryingInvariant(const std::string &originalName) const { return (mGlobalInvariant || mInvariantVaryings.count(originalName) > 0); @@ -445,10 +451,10 @@ class TSymbolTable typedef TMap PrecisionStackLevel; std::vector< PrecisionStackLevel *> precisionStack; - std::set mInvariantVaryings; + std::set mInvariantVaryings; bool mGlobalInvariant; static int uniqueIdCounter; }; -#endif // _SYMBOL_TABLE_INCLUDED_ +#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp index dcbf3cea1d..238bc97576 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp @@ -6,40 +6,91 @@ #include "compiler/translator/TranslatorESSL.h" +#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h" +#include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/OutputESSL.h" #include "angle_gl.h" TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec) - : TCompiler(type, spec, SH_ESSL_OUTPUT) { + : TCompiler(type, spec, SH_ESSL_OUTPUT) +{ } -void TranslatorESSL::translate(TIntermNode* root) { +void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) +{ + if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS) + InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType()); +} + +void TranslatorESSL::translate(TIntermNode *root, int) { TInfoSinkBase& sink = getInfoSink().obj; + int shaderVersion = getShaderVersion(); + if (shaderVersion > 100) + { + sink << "#version " << shaderVersion << " es\n"; + } + writePragma(); // Write built-in extension behaviors. writeExtensionBehavior(); + bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + + if (precisionEmulation) + { + EmulatePrecision emulatePrecision; + root->traverse(&emulatePrecision); + emulatePrecision.updateTree(); + emulatePrecision.writeEmulationHelpers(sink, SH_ESSL_OUTPUT); + } + // Write emulated built-in functions if needed. - getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( - sink, getShaderType() == GL_FRAGMENT_SHADER); + if (!getBuiltInFunctionEmulator().IsOutputEmpty()) + { + sink << "// BEGIN: Generated code for built-in function emulation\n\n"; + if (getShaderType() == GL_FRAGMENT_SHADER) + { + sink << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n" + << "#define webgl_emu_precision highp\n" + << "#else\n" + << "#define webgl_emu_precision mediump\n" + << "#endif\n\n"; + } + else + { + sink << "#define webgl_emu_precision highp\n"; + } + + getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink); + sink << "// END: Generated code for built-in function emulation\n\n"; + } // Write array bounds clamping emulation if needed. getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); // Write translated shader. - TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion()); + TOutputESSL outputESSL(sink, + getArrayIndexClampingStrategy(), + getHashFunction(), + getNameMap(), + getSymbolTable(), + shaderVersion, + precisionEmulation); root->traverse(&outputESSL); } void TranslatorESSL::writeExtensionBehavior() { TInfoSinkBase& sink = getInfoSink().obj; - const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); - for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin(); - iter != extensionBehavior.end(); ++iter) { + const TExtensionBehavior& extBehavior = getExtensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) { if (iter->second != EBhUndefined) { - if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") { + if (getResources().NV_shader_framebuffer_fetch && iter->first == "GL_EXT_shader_framebuffer_fetch") { + sink << "#extension GL_NV_shader_framebuffer_fetch : " + << getBehaviorString(iter->second) << "\n"; + } else if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") { sink << "#extension GL_NV_draw_buffers : " << getBehaviorString(iter->second) << "\n"; } else { diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h index 55766822d1..89a3e473e9 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h @@ -4,20 +4,23 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATORESSL_H_ -#define COMPILER_TRANSLATORESSL_H_ +#ifndef COMPILER_TRANSLATOR_TRANSLATORESSL_H_ +#define COMPILER_TRANSLATOR_TRANSLATORESSL_H_ #include "compiler/translator/Compiler.h" -class TranslatorESSL : public TCompiler { -public: +class TranslatorESSL : public TCompiler +{ + public: TranslatorESSL(sh::GLenum type, ShShaderSpec spec); -protected: - virtual void translate(TIntermNode* root); + protected: + void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override; -private: + virtual void translate(TIntermNode *root, int compileOptions); + + private: void writeExtensionBehavior(); }; -#endif // COMPILER_TRANSLATORESSL_H_ +#endif // COMPILER_TRANSLATOR_TRANSLATORESSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp index 6acbf7c5a8..aea3f77c4e 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp @@ -6,14 +6,69 @@ #include "compiler/translator/TranslatorGLSL.h" +#include "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h" +#include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/OutputGLSL.h" #include "compiler/translator/VersionGLSL.h" -TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec) - : TCompiler(type, spec, SH_GLSL_OUTPUT) { +namespace +{ + +// To search for what output variables are used in a fragment shader. +// We handle gl_FragColor and gl_FragData at the moment. +class TFragmentOutSearcher : public TIntermTraverser +{ + public: + TFragmentOutSearcher() + : mUsesGlFragColor(false), + mUsesGlFragData(false) + { + } + + bool usesGlFragColor() const + { + return mUsesGlFragColor; + } + + bool usesGlFragData() const + { + return mUsesGlFragData; + } + + protected: + virtual void visitSymbol(TIntermSymbol *node) override + { + if (node->getSymbol() == "gl_FragColor") + { + mUsesGlFragColor = true; + } + else if (node->getSymbol() == "gl_FragData") + { + mUsesGlFragData = true; + } + } + + private: + bool mUsesGlFragColor; + bool mUsesGlFragData; +}; + +} // namespace anonymous + +TranslatorGLSL::TranslatorGLSL(sh::GLenum type, + ShShaderSpec spec, + ShShaderOutput output) + : TCompiler(type, spec, output) { +} + +void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) +{ + if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS) + InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType()); } -void TranslatorGLSL::translate(TIntermNode* root) { +void TranslatorGLSL::translate(TIntermNode *root, int) { TInfoSinkBase& sink = getInfoSink().obj; // Write GLSL version. @@ -24,21 +79,60 @@ void TranslatorGLSL::translate(TIntermNode* root) { // Write extension behaviour as needed writeExtensionBehavior(); + bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + + if (precisionEmulation) + { + EmulatePrecision emulatePrecision; + root->traverse(&emulatePrecision); + emulatePrecision.updateTree(); + emulatePrecision.writeEmulationHelpers(sink, getOutputType()); + } + // Write emulated built-in functions if needed. - getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( - sink, false); + if (!getBuiltInFunctionEmulator().IsOutputEmpty()) + { + sink << "// BEGIN: Generated code for built-in function emulation\n\n"; + sink << "#define webgl_emu_precision\n\n"; + getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink); + sink << "// END: Generated code for built-in function emulation\n\n"; + } // Write array bounds clamping emulation if needed. getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); + // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData + // if it's core profile shaders and they are used. + if (getShaderType() == GL_FRAGMENT_SHADER && + getOutputType() == SH_GLSL_CORE_OUTPUT) + { + TFragmentOutSearcher searcher; + root->traverse(&searcher); + ASSERT(!(searcher.usesGlFragData() && searcher.usesGlFragColor())); + if (searcher.usesGlFragColor()) + { + sink << "out vec4 webgl_FragColor;\n"; + } + if (searcher.usesGlFragData()) + { + sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; + } + } + // Write translated shader. - TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion()); + TOutputGLSL outputGLSL(sink, + getArrayIndexClampingStrategy(), + getHashFunction(), + getNameMap(), + getSymbolTable(), + getShaderVersion(), + getOutputType()); root->traverse(&outputGLSL); } void TranslatorGLSL::writeVersion(TIntermNode *root) { - TVersionGLSL versionGLSL(getShaderType(), getPragma()); + TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType()); root->traverse(&versionGLSL); int version = versionGLSL.getVersion(); // We need to write version directive only if it is greater than 110. @@ -52,9 +146,9 @@ void TranslatorGLSL::writeVersion(TIntermNode *root) void TranslatorGLSL::writeExtensionBehavior() { TInfoSinkBase& sink = getInfoSink().obj; - const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); - for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin(); - iter != extensionBehavior.end(); ++iter) { + const TExtensionBehavior& extBehavior = getExtensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) { if (iter->second == EBhUndefined) continue; diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h index 766d8d910e..4a5a641096 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h @@ -4,22 +4,24 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATORGLSL_H_ -#define COMPILER_TRANSLATORGLSL_H_ +#ifndef COMPILER_TRANSLATOR_TRANSLATORGLSL_H_ +#define COMPILER_TRANSLATOR_TRANSLATORGLSL_H_ #include "compiler/translator/Compiler.h" class TranslatorGLSL : public TCompiler { public: - TranslatorGLSL(sh::GLenum type, ShShaderSpec spec); + TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); protected: - virtual void translate(TIntermNode *root); + void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override; + + virtual void translate(TIntermNode *root, int compileOptions); private: void writeVersion(TIntermNode *root); void writeExtensionBehavior(); }; -#endif // COMPILER_TRANSLATORGLSL_H_ +#endif // COMPILER_TRANSLATOR_TRANSLATORGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp index 22bf60e86e..f6275defa1 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp @@ -6,20 +6,26 @@ #include "compiler/translator/TranslatorHLSL.h" -#include "compiler/translator/InitializeParseContext.h" #include "compiler/translator/OutputHLSL.h" +#include "compiler/translator/SimplifyArrayAssignment.h" TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) : TCompiler(type, spec, output) { } -void TranslatorHLSL::translate(TIntermNode *root) +void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) { - TParseContext& parseContext = *GetGlobalParseContext(); - sh::OutputHLSL outputHLSL(parseContext, this); + const ShBuiltInResources &resources = getResources(); + int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; - outputHLSL.output(); + SimplifyArrayAssignment simplify; + root->traverse(&simplify); + + sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(), + getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions); + + outputHLSL.output(root, getInfoSink().obj); mInterfaceBlockRegisterMap = outputHLSL.getInterfaceBlockRegisterMap(); mUniformRegisterMap = outputHLSL.getUniformRegisterMap(); diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h index 11a042d83a..1920ed5755 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATORHLSL_H_ -#define COMPILER_TRANSLATORHLSL_H_ +#ifndef COMPILER_TRANSLATOR_TRANSLATORHLSL_H_ +#define COMPILER_TRANSLATOR_TRANSLATORHLSL_H_ #include "compiler/translator/Compiler.h" @@ -22,10 +22,10 @@ class TranslatorHLSL : public TCompiler unsigned int getUniformRegister(const std::string &uniformName) const; protected: - virtual void translate(TIntermNode* root); + virtual void translate(TIntermNode *root, int compileOptions); std::map mInterfaceBlockRegisterMap; std::map mUniformRegisterMap; }; -#endif // COMPILER_TRANSLATORHLSL_H_ +#endif // COMPILER_TRANSLATOR_TRANSLATORHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Types.cpp b/src/3rdparty/angle/src/compiler/translator/Types.cpp index d36936fb23..b970bf5ac4 100644 --- a/src/3rdparty/angle/src/compiler/translator/Types.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Types.cpp @@ -178,11 +178,12 @@ size_t TType::getObjectSize() const if (isArray()) { - size_t arraySize = getArraySize(); - if (arraySize > INT_MAX / totalSize) + // TODO: getArraySize() returns an int, not a size_t + size_t currentArraySize = getArraySize(); + if (currentArraySize > INT_MAX / totalSize) totalSize = INT_MAX; else - totalSize *= arraySize; + totalSize *= currentArraySize; } return totalSize; @@ -199,6 +200,17 @@ bool TStructure::containsArrays() const return false; } +bool TStructure::containsSamplers() const +{ + for (size_t i = 0; i < mFields->size(); ++i) + { + const TType *fieldType = (*mFields)[i]->type(); + if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers()) + return true; + } + return false; +} + TString TFieldListCollection::buildMangledName() const { TString mangledName(mangledNamePrefix()); diff --git a/src/3rdparty/angle/src/compiler/translator/Types.h b/src/3rdparty/angle/src/compiler/translator/Types.h index 075196daa3..044f22c3c1 100644 --- a/src/3rdparty/angle/src/compiler/translator/Types.h +++ b/src/3rdparty/angle/src/compiler/translator/Types.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _TYPES_INCLUDED -#define _TYPES_INCLUDED +#ifndef COMPILER_TRANSLATOR_TYPES_H_ +#define COMPILER_TRANSLATOR_TYPES_H_ #include "common/angleutils.h" @@ -17,7 +17,7 @@ struct TPublicType; class TType; class TSymbol; -class TField +class TField : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE(); @@ -49,7 +49,6 @@ class TField } private: - DISALLOW_COPY_AND_ASSIGN(TField); TType *mType; TString *mName; TSourceLoc mLine; @@ -62,7 +61,7 @@ inline TFieldList *NewPoolTFieldList() return new(memory) TFieldList; } -class TFieldListCollection +class TFieldListCollection : angle::NonCopyable { public: const TString &name() const @@ -113,7 +112,8 @@ class TStructure : public TFieldListCollection TStructure(const TString *name, TFieldList *fields) : TFieldListCollection(name, fields), mDeepestNesting(0), - mUniqueId(0) + mUniqueId(0), + mAtGlobalScope(false) { } @@ -124,6 +124,7 @@ class TStructure : public TFieldListCollection return mDeepestNesting; } bool containsArrays() const; + bool containsSamplers() const; bool equals(const TStructure &other) const; @@ -138,9 +139,17 @@ class TStructure : public TFieldListCollection return mUniqueId; } - private: - DISALLOW_COPY_AND_ASSIGN(TStructure); + void setAtGlobalScope(bool atGlobalScope) + { + mAtGlobalScope = atGlobalScope; + } + + bool atGlobalScope() const + { + return mAtGlobalScope; + } + private: // TODO(zmo): Find a way to get rid of the const_cast in function // setName(). At the moment keep this function private so only // friend class RegenerateStructNames may call it. @@ -159,6 +168,7 @@ class TStructure : public TFieldListCollection mutable int mDeepestNesting; int mUniqueId; + bool mAtGlobalScope; }; class TInterfaceBlock : public TFieldListCollection @@ -201,7 +211,6 @@ class TInterfaceBlock : public TFieldListCollection } private: - DISALLOW_COPY_AND_ASSIGN(TInterfaceBlock); virtual TString mangledNamePrefix() const { return "iblock-"; @@ -325,6 +334,10 @@ class TType { return primarySize > 1 && secondarySize > 1; } + bool isNonSquareMatrix() const + { + return isMatrix() && primarySize != secondarySize; + } bool isArray() const { return array ? true : false; @@ -464,6 +477,11 @@ class TType return structure ? structure->containsArrays() : false; } + bool isStructureContainingSamplers() const + { + return structure ? structure->containsSamplers() : false; + } + protected: TString buildMangledName() const; size_t getStructSize() const; @@ -584,4 +602,4 @@ struct TPublicType } }; -#endif // _TYPES_INCLUDED_ +#endif // COMPILER_TRANSLATOR_TYPES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp index 65f50c4cc3..f79f9dd7fb 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp @@ -16,7 +16,7 @@ namespace sh { -UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL) +UnfoldShortCircuit::UnfoldShortCircuit(OutputHLSL *outputHLSL) : mOutputHLSL(outputHLSL) { mTemporaryIndex = 0; } @@ -30,7 +30,7 @@ void UnfoldShortCircuit::traverse(TIntermNode *node) bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) { - TInfoSinkBase &out = mOutputHLSL->getBodyStream(); + TInfoSinkBase &out = mOutputHLSL->getInfoSink(); // If our right node doesn't have side effects, we know we don't need to unfold this // expression: there will be no short-circuiting side effects to avoid @@ -111,7 +111,7 @@ bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node) { - TInfoSinkBase &out = mOutputHLSL->getBodyStream(); + TInfoSinkBase &out = mOutputHLSL->getInfoSink(); // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" if (node->usesTernaryOperator()) diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h index 6fd3b457bd..eaceb0a0b3 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h @@ -6,8 +6,8 @@ // UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements // -#ifndef COMPILER_UNFOLDSHORTCIRCUIT_H_ -#define COMPILER_UNFOLDSHORTCIRCUIT_H_ +#ifndef COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ +#define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ #include "compiler/translator/IntermNode.h" #include "compiler/translator/ParseContext.h" @@ -19,7 +19,7 @@ class OutputHLSL; class UnfoldShortCircuit : public TIntermTraverser { public: - UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL); + UnfoldShortCircuit(OutputHLSL *outputHLSL); void traverse(TIntermNode *node); bool visitBinary(Visit visit, TIntermBinary*); @@ -29,11 +29,10 @@ class UnfoldShortCircuit : public TIntermTraverser int getNextTemporaryIndex(); protected: - TParseContext &mContext; OutputHLSL *const mOutputHLSL; int mTemporaryIndex; }; } -#endif // COMPILER_UNFOLDSHORTCIRCUIT_H_ +#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp index 29c4397d56..d548d421d2 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp @@ -50,32 +50,8 @@ bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node) } if (replacement) { - replacements.push_back( - NodeUpdateEntry(getParentNode(), node, replacement)); + mReplacements.push_back( + NodeUpdateEntry(getParentNode(), node, replacement, false)); } return true; } - -void UnfoldShortCircuitAST::updateTree() -{ - for (size_t ii = 0; ii < replacements.size(); ++ii) - { - const NodeUpdateEntry& entry = replacements[ii]; - ASSERT(entry.parent); - bool replaced = entry.parent->replaceChildNode( - entry.original, entry.replacement); - ASSERT(replaced); - - // In AST traversing, a parent is visited before its children. - // After we replace a node, if an immediate child is to - // be replaced, we need to make sure we don't update the replaced - // node; instead, we update the replacement node. - for (size_t jj = ii + 1; jj < replacements.size(); ++jj) - { - NodeUpdateEntry& entry2 = replacements[jj]; - if (entry2.parent == entry.original) - entry2.parent = entry.replacement; - } - } -} - diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h index 3acaf7ee7c..7b698ccb63 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h @@ -7,8 +7,8 @@ // operations with ternary operations. // -#ifndef COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_ -#define COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_ +#ifndef COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_ +#define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_ #include "common/angleutils.h" #include "compiler/translator/IntermNode.h" @@ -23,29 +23,6 @@ class UnfoldShortCircuitAST : public TIntermTraverser UnfoldShortCircuitAST() { } virtual bool visitBinary(Visit visit, TIntermBinary *); - - void updateTree(); - - private: - struct NodeUpdateEntry - { - NodeUpdateEntry(TIntermNode *_parent, - TIntermNode *_original, - TIntermNode *_replacement) - : parent(_parent), - original(_original), - replacement(_replacement) {} - - TIntermNode *parent; - TIntermNode *original; - TIntermNode *replacement; - }; - - // During traversing, save all the replacements that need to happen; - // then replace them by calling updateNodes(). - std::vector replacements; - - DISALLOW_COPY_AND_ASSIGN(UnfoldShortCircuitAST); }; -#endif // COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_ +#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp index 61b6ed7455..71659fe354 100644 --- a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp @@ -7,14 +7,13 @@ // 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 "common/utilities.h" #include "compiler/translator/StructureHLSL.h" -#include "compiler/translator/util.h" #include "compiler/translator/UtilsHLSL.h" -#include "compiler/translator/TranslatorHLSL.h" +#include "compiler/translator/blocklayoutHLSL.h" +#include "compiler/translator/util.h" namespace sh { @@ -61,13 +60,13 @@ static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock) return DecoratePrivate(interfaceBlock.name()) + "_type"; } -UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, TranslatorHLSL *translator) +UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector &uniforms) : mUniformRegister(0), mInterfaceBlockRegister(0), mSamplerRegister(0), mStructureHLSL(structureHLSL), - mOutputType(translator->getOutputType()), - mUniforms(translator->getUniforms()) + mOutputType(outputType), + mUniforms(uniforms) {} void UniformHLSL::reserveUniformRegisters(unsigned int registerCount) @@ -105,7 +104,7 @@ unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, con unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType); - if (gl::IsSampler(uniform->type)) + if (gl::IsSamplerType(uniform->type)) { mSamplerRegister += registerCount; } diff --git a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h index 91fa51588b..4ab9ccdf53 100644 --- a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h @@ -7,19 +7,19 @@ // Methods for GLSL to HLSL translation for uniforms and interface blocks. // -#ifndef TRANSLATOR_UNIFORMHLSL_H_ -#define TRANSLATOR_UNIFORMHLSL_H_ +#ifndef COMPILER_TRANSLATOR_UNIFORMHLSL_H_ +#define COMPILER_TRANSLATOR_UNIFORMHLSL_H_ -#include "compiler/translator/Types.h" +#include "compiler/translator/OutputHLSL.h" namespace sh { class StructureHLSL; -class UniformHLSL +class UniformHLSL : angle::NonCopyable { public: - UniformHLSL(StructureHLSL *structureHLSL, TranslatorHLSL *translator); + UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector &uniforms); void reserveUniformRegisters(unsigned int registerCount); void reserveInterfaceBlockRegisters(unsigned int registerCount); @@ -60,4 +60,4 @@ class UniformHLSL } -#endif // TRANSLATOR_UNIFORMHLSL_H_ +#endif // COMPILER_TRANSLATOR_UNIFORMHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp index de0c36ca65..94e19ac40d 100644 --- a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp @@ -175,6 +175,13 @@ TString StructNameString(const TStructure &structure) return ""; } + // For structures at global scope we use a consistent + // translation so that we can link between shader stages. + if (structure.atGlobalScope()) + { + return Decorate(structure.name()); + } + return "ss" + str(structure.uniqueId()) + "_" + structure.name(); } diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h index aaa3ddf5d2..9800a3bbf3 100644 --- a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h @@ -7,8 +7,8 @@ // Utility methods for GLSL to HLSL translation. // -#ifndef TRANSLATOR_UTILSHLSL_H_ -#define TRANSLATOR_UTILSHLSL_H_ +#ifndef COMPILER_TRANSLATOR_UTILSHLSL_H_ +#define COMPILER_TRANSLATOR_UTILSHLSL_H_ #include #include "compiler/translator/Types.h" @@ -34,4 +34,4 @@ TString QualifierString(TQualifier qualifier); } -#endif // TRANSLATOR_UTILSHLSL_H_ +#endif // COMPILER_TRANSLATOR_UTILSHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp index 896e1cd7a0..12367066e8 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp @@ -47,93 +47,6 @@ class ValidateConstIndexExpr : public TIntermTraverser TLoopStack& mLoopStack; }; -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 EOpPositive: 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 ""; -} - } // namespace anonymous ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h index e6e8a9619f..59cccb565f 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h +++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h @@ -4,6 +4,9 @@ // found in the LICENSE file. // +#ifndef COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ +#define COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ + #include "compiler/translator/IntermNode.h" #include "compiler/translator/LoopInfo.h" @@ -53,3 +56,4 @@ class ValidateLimitations : public TIntermTraverser TLoopStack mLoopStack; }; +#endif // COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h index 0f808dbb97..1538e0f157 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h +++ b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h @@ -4,6 +4,9 @@ // found in the LICENSE file. // +#ifndef COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ +#define COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ + #include "compiler/translator/IntermNode.h" #include @@ -31,3 +34,5 @@ class ValidateOutputs : public TIntermTraverser void error(TSourceLoc loc, const char *reason, const char* token); }; + +#endif // COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp new file mode 100644 index 0000000000..9a4ed33632 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp @@ -0,0 +1,200 @@ +// +// Copyright (c) 2002-2015 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/ValidateSwitch.h" + +#include "compiler/translator/ParseContext.h" + +bool ValidateSwitch::validate(TBasicType switchType, TParseContext *context, + TIntermAggregate *statementList, const TSourceLoc &loc) +{ + ValidateSwitch validate(switchType, context); + ASSERT(statementList); + statementList->traverse(&validate); + return validate.validateInternal(loc); +} + +ValidateSwitch::ValidateSwitch(TBasicType switchType, TParseContext *context) + : TIntermTraverser(true, false, true), + mSwitchType(switchType), + mContext(context), + mCaseTypeMismatch(false), + mFirstCaseFound(false), + mStatementBeforeCase(false), + mLastStatementWasCase(false), + mControlFlowDepth(0), + mCaseInsideControlFlow(false), + mDefaultCount(0), + mDuplicateCases(false) +{} + +void ValidateSwitch::visitSymbol(TIntermSymbol *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; +} + +void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *) +{ + // Conditions of case labels are not traversed, so this is some other constant + // Could be just a statement like "0;" + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; +} + +bool ValidateSwitch::visitBinary(Visit, TIntermBinary *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitUnary(Visit, TIntermUnary *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitSelection(Visit visit, TIntermSelection *) +{ + if (visit == PreVisit) + ++mControlFlowDepth; + if (visit == PostVisit) + --mControlFlowDepth; + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + // Don't go into nested switch statements + return false; +} + +bool ValidateSwitch::visitCase(Visit, TIntermCase *node) +{ + const char *nodeStr = node->hasCondition() ? "case" : "default"; + if (mControlFlowDepth > 0) + { + mContext->error(node->getLine(), "label statement nested inside control flow", nodeStr); + mCaseInsideControlFlow = true; + } + mFirstCaseFound = true; + mLastStatementWasCase = true; + if (!node->hasCondition()) + { + ++mDefaultCount; + if (mDefaultCount > 1) + { + mContext->error(node->getLine(), "duplicate default label", nodeStr); + } + } + else + { + TIntermConstantUnion *condition = node->getCondition()->getAsConstantUnion(); + if (condition == nullptr) + { + // This can happen in error cases. + return false; + } + TBasicType conditionType = condition->getBasicType(); + if (conditionType != mSwitchType) + { + mContext->error(condition->getLine(), + "case label type does not match switch init-expression type", nodeStr); + mCaseTypeMismatch = true; + } + + if (conditionType == EbtInt) + { + int iConst = condition->getIConst(0); + if (mCasesSigned.find(iConst) != mCasesSigned.end()) + { + mContext->error(condition->getLine(), "duplicate case label", nodeStr); + mDuplicateCases = true; + } + else + { + mCasesSigned.insert(iConst); + } + } + else if (conditionType == EbtUInt) + { + unsigned int uConst = condition->getUConst(0); + if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end()) + { + mContext->error(condition->getLine(), "duplicate case label", nodeStr); + mDuplicateCases = true; + } + else + { + mCasesUnsigned.insert(uConst); + } + } + // Other types are possible only in error cases, where the error has already been generated + // when parsing the case statement. + } + // Don't traverse the condition of the case statement + return false; +} + +bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *) +{ + if (getParentNode() != nullptr) + { + // This is not the statementList node, but some other node. + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + } + return true; +} + +bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *) +{ + if (visit == PreVisit) + ++mControlFlowDepth; + if (visit == PostVisit) + --mControlFlowDepth; + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitBranch(Visit, TIntermBranch *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::validateInternal(const TSourceLoc &loc) +{ + if (mStatementBeforeCase) + { + mContext->error(loc, + "statement before the first label", "switch"); + } + if (mLastStatementWasCase) + { + mContext->error(loc, + "no statement between the last label and the end of the switch statement", "switch"); + } + return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow && + !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases; +} diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h new file mode 100644 index 0000000000..88b68a500e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2002-2015 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_VALIDATESWITCH_H_ +#define COMPILER_TRANSLATOR_VALIDATESWITCH_H_ + +#include "compiler/translator/IntermNode.h" + +struct TParseContext; + +class ValidateSwitch : public TIntermTraverser +{ + public: + // Check for errors and output messages any remaining errors on the context. + // Returns true if there are no errors. + static bool validate(TBasicType switchType, TParseContext *context, + TIntermAggregate *statementList, const TSourceLoc &loc); + + void visitSymbol(TIntermSymbol *) override; + void visitConstantUnion(TIntermConstantUnion *) override; + bool visitBinary(Visit, TIntermBinary *) override; + bool visitUnary(Visit, TIntermUnary *) override; + bool visitSelection(Visit visit, TIntermSelection *) override; + bool visitSwitch(Visit, TIntermSwitch *) override; + bool visitCase(Visit, TIntermCase *node) override; + bool visitAggregate(Visit, TIntermAggregate *) override; + bool visitLoop(Visit visit, TIntermLoop *) override; + bool visitBranch(Visit, TIntermBranch *) override; + + private: + ValidateSwitch(TBasicType switchType, TParseContext *context); + + bool validateInternal(const TSourceLoc &loc); + + TBasicType mSwitchType; + TParseContext *mContext; + bool mCaseTypeMismatch; + bool mFirstCaseFound; + bool mStatementBeforeCase; + bool mLastStatementWasCase; + int mControlFlowDepth; + bool mCaseInsideControlFlow; + int mDefaultCount; + std::set mCasesSigned; + std::set mCasesUnsigned; + bool mDuplicateCases; +}; + +#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp index d8e13788b7..cf229ec96a 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp @@ -142,8 +142,10 @@ CollectVariables::CollectVariables(std::vector *attribs, mPointCoordAdded(false), mFrontFacingAdded(false), mFragCoordAdded(false), + mInstanceIDAdded(false), mPositionAdded(false), mPointSizeAdded(false), + mLastFragDataAdded(false), mHashFunction(hashFunction), mSymbolTable(symbolTable) { @@ -249,6 +251,22 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) mPointCoordAdded = true; } return; + case EvqInstanceID: + if (!mInstanceIDAdded) + { + Attribute info; + const char kName[] = "gl_InstanceID"; + info.name = kName; + info.mappedName = kName; + info.type = GL_INT; + info.arraySize = 0; + info.precision = GL_HIGH_INT; // Defined by spec. + info.staticUse = true; + info.location = -1; + mAttribs->push_back(info); + mInstanceIDAdded = true; + } + return; case EvqPosition: if (!mPositionAdded) { @@ -281,6 +299,22 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) mPointSizeAdded = true; } return; + case EvqLastFragData: + if (!mLastFragDataAdded) + { + Varying info; + const char kName[] = "gl_LastFragData"; + info.name = kName; + info.mappedName = kName; + info.type = GL_FLOAT_VEC4; + info.arraySize = static_cast(mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))->getConstPointer()->getIConst(); + info.precision = GL_MEDIUM_FLOAT; // Defined by spec. + info.staticUse = true; + info.isInvariant = mSymbolTable.isVaryingInvariant(kName); + mVaryings->push_back(info); + mLastFragDataAdded = true; + } + return; default: break; } @@ -301,8 +335,6 @@ class NameHashingTraverser : public GetVariableTraverser {} private: - DISALLOW_COPY_AND_ASSIGN(NameHashingTraverser); - virtual void visitVariable(ShaderVariable *variable) { TString stringName = TString(variable->name.c_str()); diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h index 92d376d879..bb1328a507 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h +++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_VARIABLE_INFO_H_ -#define COMPILER_VARIABLE_INFO_H_ +#ifndef COMPILER_TRANSLATOR_VARIABLEINFO_H_ +#define COMPILER_TRANSLATOR_VARIABLEINFO_H_ #include @@ -51,8 +51,10 @@ class CollectVariables : public TIntermTraverser bool mFrontFacingAdded; bool mFragCoordAdded; + bool mInstanceIDAdded; bool mPositionAdded; bool mPointSizeAdded; + bool mLastFragDataAdded; ShHashFunction64 mHashFunction; @@ -65,4 +67,4 @@ void ExpandUniforms(const std::vector &compact, } -#endif // COMPILER_VARIABLE_INFO_H_ +#endif // COMPILER_TRANSLATOR_VARIABLEINFO_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/VariablePacker.h b/src/3rdparty/angle/src/compiler/translator/VariablePacker.h index 1de5332d8a..9c80eea618 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariablePacker.h +++ b/src/3rdparty/angle/src/compiler/translator/VariablePacker.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _VARIABLEPACKER_INCLUDED_ -#define _VARIABLEPACKER_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_VARIABLEPACKER_H_ +#define COMPILER_TRANSLATOR_VARIABLEPACKER_H_ #include #include "compiler/translator/VariableInfo.h" @@ -38,4 +38,4 @@ class VariablePacker { std::vector rows_; }; -#endif // _VARIABLEPACKER_INCLUDED_ +#endif // COMPILER_TRANSLATOR_VARIABLEPACKER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp index 05b111a7a7..f6f568897d 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp @@ -8,6 +8,7 @@ static const int GLSL_VERSION_110 = 110; static const int GLSL_VERSION_120 = 120; +static const int GLSL_VERSION_150 = 150; // We need to scan for the following: // 1. "invariant" keyword: This can occur in both - vertex and fragment shaders @@ -26,12 +27,22 @@ static const int GLSL_VERSION_120 = 120; // GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that // are built-in types, entire structures or arrays... are all l-values." // -TVersionGLSL::TVersionGLSL(sh::GLenum type, const TPragma &pragma) +TVersionGLSL::TVersionGLSL(sh::GLenum type, + const TPragma &pragma, + ShShaderOutput output) { - if (pragma.stdgl.invariantAll) - mVersion = GLSL_VERSION_120; + if (output == SH_GLSL_CORE_OUTPUT) + { + mVersion = GLSL_VERSION_150; + } else - mVersion = GLSL_VERSION_110; + { + ASSERT(output == SH_GLSL_COMPATIBILITY_OUTPUT); + if (pragma.stdgl.invariantAll) + mVersion = GLSL_VERSION_120; + else + mVersion = GLSL_VERSION_110; + } } void TVersionGLSL::visitSymbol(TIntermSymbol *node) diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h index 72368e39d6..2b63d5f25d 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h @@ -29,14 +29,16 @@ class TVersionGLSL : public TIntermTraverser { public: - TVersionGLSL(sh::GLenum type, const TPragma &pragma); - - // Returns 120 if the following is used the shader: - // - "invariant", - // - "gl_PointCoord", - // - matrix/matrix constructors - // - array "out" parameters - // Else 110 is returned. + TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output); + + // If output is core profile, returns 150. + // If output is legacy profile, + // Returns 120 if the following is used the shader: + // - "invariant", + // - "gl_PointCoord", + // - matrix/matrix constructors + // - array "out" parameters + // Else 110 is returned. int getVersion() { return mVersion; } virtual void visitSymbol(TIntermSymbol *); diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp b/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp new file mode 100644 index 0000000000..7c74105680 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp @@ -0,0 +1,123 @@ +// +// Copyright (c) 2013-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. +// +// blocklayout.cpp: +// Implementation for block layout classes and methods. +// + +#include "compiler/translator/blocklayout.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace sh +{ + +BlockLayoutEncoder::BlockLayoutEncoder() + : mCurrentOffset(0) +{ +} + +BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix) +{ + int arrayStride; + int matrixStride; + + getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride); + + const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix); + + advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride); + + return memberInfo; +} + +// static +size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info) +{ + return (info.offset / BytesPerComponent) / ComponentsPerRegister; +} + +// static +size_t BlockLayoutEncoder::getBlockRegisterElement(const BlockMemberInfo &info) +{ + return (info.offset / BytesPerComponent) % ComponentsPerRegister; +} + +void BlockLayoutEncoder::nextRegister() +{ + mCurrentOffset = rx::roundUp(mCurrentOffset, ComponentsPerRegister); +} + +Std140BlockEncoder::Std140BlockEncoder() +{ +} + +void Std140BlockEncoder::enterAggregateType() +{ + nextRegister(); +} + +void Std140BlockEncoder::exitAggregateType() +{ + nextRegister(); +} + +void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) +{ + // We assume we are only dealing with 4 byte components (no doubles or half-words currently) + ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); + + size_t baseAlignment = 0; + int matrixStride = 0; + int arrayStride = 0; + + if (gl::IsMatrixType(type)) + { + baseAlignment = ComponentsPerRegister; + matrixStride = ComponentsPerRegister; + + if (arraySize > 0) + { + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + arrayStride = ComponentsPerRegister * numRegisters; + } + } + else if (arraySize > 0) + { + baseAlignment = ComponentsPerRegister; + arrayStride = ComponentsPerRegister; + } + else + { + const int numComponents = gl::VariableComponentCount(type); + baseAlignment = (numComponents == 3 ? 4u : static_cast(numComponents)); + } + + mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment); + + *matrixStrideOut = matrixStride; + *arrayStrideOut = arrayStride; +} + +void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) +{ + if (arraySize > 0) + { + mCurrentOffset += arrayStride * arraySize; + } + else if (gl::IsMatrixType(type)) + { + ASSERT(matrixStride == ComponentsPerRegister); + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + mCurrentOffset += ComponentsPerRegister * numRegisters; + } + else + { + mCurrentOffset += gl::VariableComponentCount(type); + } +} + +} diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayout.h b/src/3rdparty/angle/src/compiler/translator/blocklayout.h new file mode 100644 index 0000000000..c11357fe66 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/blocklayout.h @@ -0,0 +1,94 @@ +// +// Copyright (c) 2013-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. +// +// blocklayout.h: +// Methods and classes related to uniform layout and packing in GLSL and HLSL. +// + +#ifndef COMMON_BLOCKLAYOUT_H_ +#define COMMON_BLOCKLAYOUT_H_ + +#include +#include + +#include "angle_gl.h" +#include + +namespace sh +{ +struct ShaderVariable; +struct InterfaceBlockField; +struct Uniform; +struct Varying; +struct InterfaceBlock; + +struct COMPILER_EXPORT BlockMemberInfo +{ + BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix) + : offset(offset), + arrayStride(arrayStride), + matrixStride(matrixStride), + isRowMajorMatrix(isRowMajorMatrix) + {} + + static BlockMemberInfo getDefaultBlockInfo() + { + return BlockMemberInfo(-1, -1, -1, false); + } + + int offset; + int arrayStride; + int matrixStride; + bool isRowMajorMatrix; +}; + +class COMPILER_EXPORT BlockLayoutEncoder +{ + public: + BlockLayoutEncoder(); + + BlockMemberInfo encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix); + + size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; } + size_t getCurrentRegister() const { return mCurrentOffset / ComponentsPerRegister; } + size_t getCurrentElement() const { return mCurrentOffset % ComponentsPerRegister; } + + virtual void enterAggregateType() = 0; + virtual void exitAggregateType() = 0; + + static const size_t BytesPerComponent = 4u; + static const unsigned int ComponentsPerRegister = 4u; + + static size_t getBlockRegister(const BlockMemberInfo &info); + static size_t getBlockRegisterElement(const BlockMemberInfo &info); + + protected: + size_t mCurrentOffset; + + void nextRegister(); + + virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0; + virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0; +}; + +// Block layout according to the std140 block layout +// See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification + +class COMPILER_EXPORT Std140BlockEncoder : public BlockLayoutEncoder +{ + public: + Std140BlockEncoder(); + + virtual void enterAggregateType(); + virtual void exitAggregateType(); + + protected: + virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut); + virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride); +}; + +} + +#endif // COMMON_BLOCKLAYOUT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp new file mode 100644 index 0000000000..f32cf2cf89 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp @@ -0,0 +1,165 @@ +// +// Copyright (c) 2013-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. +// +// blocklayout.cpp: +// Implementation for block layout classes and methods. +// + +#include "compiler/translator/blocklayoutHLSL.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace sh +{ + +HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy) + : mEncoderStrategy(strategy), + mTransposeMatrices(false) +{ +} + +void HLSLBlockEncoder::enterAggregateType() +{ + nextRegister(); +} + +void HLSLBlockEncoder::exitAggregateType() +{ +} + +void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) +{ + GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); + + // We assume we are only dealing with 4 byte components (no doubles or half-words currently) + ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); + + int matrixStride = 0; + int arrayStride = 0; + + // if variables are not to be packed, or we're about to + // pack a matrix or array, skip to the start of the next + // register + if (!isPacked() || + gl::IsMatrixType(type) || + arraySize > 0) + { + nextRegister(); + } + + if (gl::IsMatrixType(type)) + { + matrixStride = ComponentsPerRegister; + + if (arraySize > 0) + { + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + arrayStride = ComponentsPerRegister * numRegisters; + } + } + else if (arraySize > 0) + { + arrayStride = ComponentsPerRegister; + } + else if (isPacked()) + { + int numComponents = gl::VariableComponentCount(type); + if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister) + { + nextRegister(); + } + } + + *matrixStrideOut = matrixStride; + *arrayStrideOut = arrayStride; +} + +void HLSLBlockEncoder::advanceOffset(GLenum typeIn, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) +{ + GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); + + if (arraySize > 0) + { + mCurrentOffset += arrayStride * (arraySize - 1); + } + + if (gl::IsMatrixType(type)) + { + ASSERT(matrixStride == ComponentsPerRegister); + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix); + mCurrentOffset += ComponentsPerRegister * (numRegisters - 1); + mCurrentOffset += numComponents; + } + else if (isPacked()) + { + mCurrentOffset += gl::VariableComponentCount(type); + } + else + { + mCurrentOffset += ComponentsPerRegister; + } +} + +void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters) +{ + mCurrentOffset += (numRegisters * ComponentsPerRegister); +} + +HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(ShShaderOutput outputType) +{ + switch (outputType) + { + case SH_HLSL9_OUTPUT: return ENCODE_LOOSE; + case SH_HLSL11_OUTPUT: return ENCODE_PACKED; + default: UNREACHABLE(); return ENCODE_PACKED; + } +} + +template +void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder) +{ + if (variable.isStruct()) + { + for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++) + { + encoder->enterAggregateType(); + + for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++) + { + HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder); + } + + encoder->exitAggregateType(); + } + } + else + { + // We operate only on varyings and uniforms, which do not have matrix layout qualifiers + encoder->encodeType(variable.type, variable.arraySize, false); + } +} + +unsigned int HLSLVariableRegisterCount(const Varying &variable, bool transposeMatrices) +{ + HLSLBlockEncoder encoder(HLSLBlockEncoder::ENCODE_PACKED); + encoder.setTransposeMatrices(transposeMatrices); + HLSLVariableRegisterCount(variable, &encoder); + + const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); + return static_cast(rx::roundUp(encoder.getBlockSize(), registerBytes) / registerBytes); +} + +unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType) +{ + HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType)); + HLSLVariableRegisterCount(variable, &encoder); + + const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); + return static_cast(rx::roundUp(encoder.getBlockSize(), registerBytes) / registerBytes); +} + +} diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h new file mode 100644 index 0000000000..c61cb1ae57 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2013-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. +// +// blocklayout.h: +// Methods and classes related to uniform layout and packing in GLSL and HLSL. +// + +#ifndef COMMON_BLOCKLAYOUTHLSL_H_ +#define COMMON_BLOCKLAYOUTHLSL_H_ + +#include +#include + +#include "angle_gl.h" +#include "blocklayout.h" +#include + +namespace sh +{ +// Block layout packed according to the D3D9 or default D3D10+ register packing rules +// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx +// The strategy should be ENCODE_LOOSE for D3D9 constant blocks, and ENCODE_PACKED +// for everything else (D3D10+ constant blocks and all attributes/varyings). + +class COMPILER_EXPORT HLSLBlockEncoder : public BlockLayoutEncoder +{ + public: + enum HLSLBlockEncoderStrategy + { + ENCODE_PACKED, + ENCODE_LOOSE + }; + + HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy); + + virtual void enterAggregateType(); + virtual void exitAggregateType(); + void skipRegisters(unsigned int numRegisters); + + bool isPacked() const { return mEncoderStrategy == ENCODE_PACKED; } + void setTransposeMatrices(bool enabled) { mTransposeMatrices = enabled; } + + static HLSLBlockEncoderStrategy GetStrategyFor(ShShaderOutput outputType); + + protected: + virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut); + virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride); + + HLSLBlockEncoderStrategy mEncoderStrategy; + bool mTransposeMatrices; +}; + +// This method returns the number of used registers for a ShaderVariable. It is dependent on the HLSLBlockEncoder +// class to count the number of used registers in a struct (which are individually packed according to the same rules). +COMPILER_EXPORT unsigned int HLSLVariableRegisterCount(const Varying &variable, bool transposeMatrices); +COMPILER_EXPORT unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType); + +} + +#endif // COMMON_BLOCKLAYOUTHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/compilerdebug.h b/src/3rdparty/angle/src/compiler/translator/compilerdebug.h index 7a371516af..84a12ad2f8 100644 --- a/src/3rdparty/angle/src/compiler/translator/compilerdebug.h +++ b/src/3rdparty/angle/src/compiler/translator/compilerdebug.h @@ -6,8 +6,8 @@ // debug.h: Debugging utilities. -#ifndef COMPILER_DEBUG_H_ -#define COMPILER_DEBUG_H_ +#ifndef COMPILER_TRANSLATOR_COMPILERDEBUG_H_ +#define COMPILER_TRANSLATOR_COMPILERDEBUG_H_ #include @@ -49,5 +49,5 @@ void Trace(const char* format, ...); assert(false); \ } while(0) -#endif // COMPILER_DEBUG_H_ +#endif // COMPILER_TRANSLATOR_COMPILERDEBUG_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h index bc25fe7cbc..22db633678 100644 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h +++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H -#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H +#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ +#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ #include "compiler/translator/IntermNode.h" @@ -186,7 +186,7 @@ private: // // When using this, just fill in the methods for nodes you want visited. // -class TDependencyGraphTraverser { +class TDependencyGraphTraverser : angle::NonCopyable { public: TDependencyGraphTraverser() : mDepth(0) {} @@ -209,4 +209,4 @@ private: TGraphNodeSet mVisited; }; -#endif +#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h index b76f075e68..f7b3bd4b43 100644 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h +++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H -#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H +#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ +#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ #include "compiler/translator/depgraph/DependencyGraph.h" @@ -104,7 +104,7 @@ class TDependencyGraphBuilder : public TIntermTraverser // 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 + class TNodeSetMaintainer : angle::NonCopyable { public: TNodeSetMaintainer(TDependencyGraphBuilder *factory) @@ -122,7 +122,7 @@ class TDependencyGraphBuilder : public TIntermTraverser // 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 + class TNodeSetPropagatingMaintainer : angle::NonCopyable { public: TNodeSetPropagatingMaintainer(TDependencyGraphBuilder *factory) @@ -147,7 +147,7 @@ class TDependencyGraphBuilder : public TIntermTraverser // kRightSubtree will never be replaced by a real symbol because we are tracking // the leftmost symbol. // - class TLeftmostSymbolMaintainer + class TLeftmostSymbolMaintainer : angle::NonCopyable { public: TLeftmostSymbolMaintainer( @@ -196,4 +196,4 @@ class TDependencyGraphBuilder : public TIntermTraverser TSymbolStack mLeftmostSymbols; }; -#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H +#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h index c3a4112278..b201e0a671 100644 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h +++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h @@ -4,27 +4,28 @@ // found in the LICENSE file. // -#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H -#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H +#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ +#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ #include "compiler/translator/depgraph/DependencyGraph.h" #include "compiler/translator/InfoSink.h" -class TDependencyGraphOutput : public TDependencyGraphTraverser { -public: +class TDependencyGraphOutput : public TDependencyGraphTraverser +{ + public: TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {} - virtual void visitSymbol(TGraphSymbol* symbol); - virtual void visitArgument(TGraphArgument* parameter); - virtual void visitFunctionCall(TGraphFunctionCall* functionCall); - virtual void visitSelection(TGraphSelection* selection); - virtual void visitLoop(TGraphLoop* loop); - virtual void visitLogicalOp(TGraphLogicalOp* logicalOp); + void visitSymbol(TGraphSymbol* symbol) override; + void visitArgument(TGraphArgument* parameter) override; + void visitFunctionCall(TGraphFunctionCall* functionCall) override; + void visitSelection(TGraphSelection* selection) override; + void visitLoop(TGraphLoop* loop) override; + void visitLogicalOp(TGraphLogicalOp* logicalOp) override; void outputAllSpanningTrees(TDependencyGraph& graph); -private: + private: void outputIndentation(); TInfoSinkBase& mSink; }; -#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H +#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.h b/src/3rdparty/angle/src/compiler/translator/glslang.h index f221199093..db31e6946c 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.h +++ b/src/3rdparty/angle/src/compiler/translator/glslang.h @@ -4,6 +4,9 @@ // found in the LICENSE file. // +#ifndef COMPILER_TRANSLATOR_GLSLANG_H_ +#define COMPILER_TRANSLATOR_GLSLANG_H_ + struct TParseContext; extern int glslang_initialize(TParseContext* context); extern int glslang_finalize(TParseContext* context); @@ -14,3 +17,4 @@ extern int glslang_scan(size_t count, TParseContext* context); extern int glslang_parse(TParseContext* context); +#endif // COMPILER_TRANSLATOR_GLSLANG_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.l b/src/3rdparty/angle/src/compiler/translator/glslang.l index 518b78df11..ee4d28b6d6 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.l +++ b/src/3rdparty/angle/src/compiler/translator/glslang.l @@ -32,6 +32,7 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). #pragma warning(disable: 4189) #pragma warning(disable: 4505) #pragma warning(disable: 4701) +#pragma warning(disable: 4702) #endif } @@ -70,6 +71,7 @@ static int floatsuffix_check(TParseContext* context); %option noyywrap nounput never-interactive %option yylineno reentrant bison-bridge bison-locations %option extra-type="TParseContext*" +%x FIELDS D [0-9] L [a-zA-Z_] @@ -358,7 +360,7 @@ O [0-7] ")" { return RIGHT_PAREN; } ("["|"<:") { return LEFT_BRACKET; } ("]"|":>") { return RIGHT_BRACKET; } -"." { return DOT; } +"." { BEGIN(FIELDS); return DOT; } "!" { return BANG; } "-" { return DASH; } "~" { return TILDE; } @@ -373,9 +375,16 @@ O [0-7] "&" { return AMPERSAND; } "?" { return QUESTION; } +{L}({L}|{D})* { + BEGIN(INITIAL); + yylval->lex.string = NewPoolTString(yytext); + return FIELD_SELECTION; +} +[ \t\v\f\r] {} + [ \t\v\n\f\r] { } -<> { yyterminate(); } -. { assert(false); return 0; } +<*><> { yyterminate(); } +<*>. { assert(false); return 0; } %% @@ -492,8 +501,8 @@ int floatsuffix_check(TParseContext* context) return(FLOATCONSTANT); } -void yyerror(YYLTYPE* lloc, TParseContext* context, const char* reason) { - context->error(*lloc, reason, yyget_text(context->scanner)); +void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* reason) { + context->error(*lloc, reason, yyget_text(scanner)); context->recover(); } diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.y b/src/3rdparty/angle/src/compiler/translator/glslang.y index e271de978c..6024898cb0 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.y +++ b/src/3rdparty/angle/src/compiler/translator/glslang.y @@ -32,6 +32,7 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). #pragma warning(disable: 4189) #pragma warning(disable: 4505) #pragma warning(disable: 4701) +#pragma warning(disable: 4702) #endif #include "angle_gl.h" @@ -41,12 +42,11 @@ 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} +%param {void *scanner} +%define api.pure full %locations %code requires { @@ -72,6 +72,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). TIntermNodePair nodePair; TIntermTyped* intermTypedNode; TIntermAggregate* intermAggregate; + TIntermSwitch* intermSwitch; + TIntermCase* intermCase; }; union { TPublicType type; @@ -88,11 +90,11 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). %{ extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner); -extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason); +extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, const char* reason); #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ - if (YYID(N)) { \ + if (N) { \ (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ (Current).last_file = YYRHSLOC(Rhs, N).last_file; \ @@ -179,6 +181,8 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason) %type declaration external_declaration %type for_init_statement compound_statement_no_new_scope %type selection_rest_statement for_rest_statement +%type switch_statement +%type case_label %type iteration_statement jump_statement statement_no_new_scope statement_with_scope %type single_declaration init_declarator_list @@ -269,28 +273,14 @@ postfix_expression | function_call { $$ = $1; } - | postfix_expression DOT identifier { + | postfix_expression DOT FIELD_SELECTION { $$ = context->addFieldSelectionExpression($1, @2, *$3.string, @3); } | postfix_expression INC_OP { - if (context->lValueErrorCheck(@2, "++", $1)) - context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, @2); - if ($$ == 0) { - context->unaryOpError(@2, "++", $1->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addUnaryMathLValue(EOpPostIncrement, $1, @2); } | postfix_expression DEC_OP { - if (context->lValueErrorCheck(@2, "--", $1)) - context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, @2); - if ($$ == 0) { - context->unaryOpError(@2, "--", $1->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addUnaryMathLValue(EOpPostDecrement, $1, @2); } ; @@ -304,118 +294,12 @@ integer_expression function_call : function_call_or_method { - TFunction* fnCall = $1.function; - TOperator op = fnCall->getBuiltInOp(); - - if (op != EOpNull) + bool fatalError = false; + $$ = context->addFunctionCallOrMethod($1.function, $1.intermNode, @1, &fatalError); + if (fatalError) { - // - // Then this should be a constructor. - // Don't go through the symbol table for constructors. - // Their parameters will be verified algorithmically. - // - TType type(EbtVoid, EbpUndefined); // use this to get the type back - if (context->constructorErrorCheck(@1, $1.intermNode, *fnCall, op, &type)) { - $$ = 0; - } else { - // - // It's a constructor, of type 'type'. - // - $$ = context->addConstructor($1.intermNode, &type, op, fnCall, @1); - } - - if ($$ == 0) { - context->recover(); - $$ = context->intermediate.setAggregateOperator(0, op, @1); - } - $$->setType(type); - } else { - // - // Not a constructor. Find it in the symbol table. - // - const TFunction* fnCandidate; - bool builtIn; - fnCandidate = context->findFunction(@1, fnCall, context->shaderVersion, &builtIn); - if (fnCandidate) { - // - // A declared function. - // - if (builtIn && !fnCandidate->getExtension().empty() && - context->extensionErrorCheck(@1, fnCandidate->getExtension())) { - context->recover(); - } - op = fnCandidate->getBuiltInOp(); - if (builtIn && op != EOpNull) { - // - // A function call mapped to a built-in operation. - // - if (fnCandidate->getParamCount() == 1) { - // - // Treat it like a built-in unary operator. - // - $$ = context->intermediate.addUnaryMath(op, $1.intermNode, @1); - const TType& returnType = fnCandidate->getReturnType(); - if (returnType.getBasicType() == EbtBool) { - // Bool types should not have precision, so we'll override any precision - // that might have been set by addUnaryMath. - $$->setType(returnType); - } else { - // addUnaryMath has set the precision of the node based on the operand. - $$->setTypePreservePrecision(returnType); - } - if ($$ == 0) { - std::stringstream extraInfoStream; - extraInfoStream << "built in unary operator function. Type: " << static_cast($1.intermNode)->getCompleteString(); - std::string extraInfo = extraInfoStream.str(); - context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); - YYERROR; - } - } else { - TIntermAggregate *aggregate = context->intermediate.setAggregateOperator($1.intermAggregate, op, @1); - aggregate->setType(fnCandidate->getReturnType()); - aggregate->setPrecisionFromChildren(); - $$ = aggregate; - } - } else { - // This is a real function call - - TIntermAggregate *aggregate = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, @1); - aggregate->setType(fnCandidate->getReturnType()); - - // this is how we know whether the given function is a builtIn function or a user defined function - // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also - // if builtIn == true, it's definitely a builtIn function with EOpNull - if (!builtIn) - aggregate->setUserDefined(); - aggregate->setName(fnCandidate->getMangledName()); - - // This needs to happen after the name is set - if (builtIn) - aggregate->setBuiltInFunctionPrecision(); - - $$ = aggregate; - - TQualifier qual; - 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())) { - context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); - context->recover(); - } - } - } - } - } else { - // error message was put out by PaFindFunction() - // Put on a dummy node for error recovery - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setFConst(0.0f); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1); - context->recover(); - } + YYERROR; } - delete fnCall; } ; @@ -484,6 +368,13 @@ function_identifier TFunction *function = new TFunction($1.string, type); $$ = function; } + | FIELD_SELECTION { + if (context->reservedErrorCheck(@1, *$1.string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } ; unary_expression @@ -491,40 +382,14 @@ unary_expression $$ = $1; } | INC_OP unary_expression { - if (context->lValueErrorCheck(@1, "++", $2)) - context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, @1); - if ($$ == 0) { - context->unaryOpError(@1, "++", $2->getCompleteString()); - context->recover(); - $$ = $2; - } + $$ = context->addUnaryMathLValue(EOpPreIncrement, $2, @1); } | DEC_OP unary_expression { - if (context->lValueErrorCheck(@1, "--", $2)) - context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, @1); - if ($$ == 0) { - context->unaryOpError(@1, "--", $2->getCompleteString()); - context->recover(); - $$ = $2; - } + $$ = context->addUnaryMathLValue(EOpPreDecrement, $2, @1); } | unary_operator unary_expression { if ($1.op != EOpNull) { - $$ = context->intermediate.addUnaryMath($1.op, $2, @1); - if ($$ == 0) { - const char* errorOp = ""; - switch($1.op) { - case EOpNegative: errorOp = "-"; break; - case EOpPositive: errorOp = "+"; break; - case EOpLogicalNot: errorOp = "!"; break; - default: break; - } - context->unaryOpError(@1, errorOp, $2->getCompleteString()); - context->recover(); - $$ = $2; - } + $$ = context->addUnaryMath($1.op, $2, @1); } else $$ = $2; } @@ -535,172 +400,117 @@ unary_operator : PLUS { $$.op = EOpPositive; } | DASH { $$.op = EOpNegative; } | BANG { $$.op = EOpLogicalNot; } + | TILDE { + ES3_ONLY("~", @$, "bit-wise operator"); + $$.op = EOpBitwiseNot; + } ; // Grammar Note: No '*' or '&' unary ops. Pointers are not supported. multiplicative_expression : unary_expression { $$ = $1; } | multiplicative_expression STAR unary_expression { - $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "*", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addBinaryMath(EOpMul, $1, $3, @2); } | multiplicative_expression SLASH unary_expression { - $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "/", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addBinaryMath(EOpDiv, $1, $3, @2); + } + | multiplicative_expression PERCENT unary_expression { + ES3_ONLY("%", @2, "integer modulus operator"); + $$ = context->addBinaryMath(EOpIMod, $1, $3, @2); } ; additive_expression : multiplicative_expression { $$ = $1; } | additive_expression PLUS multiplicative_expression { - $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "+", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addBinaryMath(EOpAdd, $1, $3, @2); } | additive_expression DASH multiplicative_expression { - $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "-", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addBinaryMath(EOpSub, $1, $3, @2); } ; shift_expression : additive_expression { $$ = $1; } + | shift_expression LEFT_OP additive_expression { + ES3_ONLY("<<", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitShiftLeft, $1, $3, @2); + } + | shift_expression RIGHT_OP additive_expression { + ES3_ONLY(">>", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitShiftRight, $1, $3, @2); + } ; relational_expression : shift_expression { $$ = $1; } | relational_expression LEFT_ANGLE shift_expression { - $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "<", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLessThan, $1, $3, @2); } | relational_expression RIGHT_ANGLE shift_expression { - $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, ">", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpGreaterThan, $1, $3, @2); } | relational_expression LE_OP shift_expression { - $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "<=", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLessThanEqual, $1, $3, @2); } | relational_expression GE_OP shift_expression { - $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, ">=", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpGreaterThanEqual, $1, $3, @2); } ; equality_expression : relational_expression { $$ = $1; } | equality_expression EQ_OP relational_expression { - $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "==", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpEqual, $1, $3, @2); } | equality_expression NE_OP relational_expression { - $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "!=", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpNotEqual, $1, $3, @2); } ; and_expression : equality_expression { $$ = $1; } + | and_expression AMPERSAND equality_expression { + ES3_ONLY("&", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitwiseAnd, $1, $3, @2); + } ; exclusive_or_expression : and_expression { $$ = $1; } + | exclusive_or_expression CARET and_expression { + ES3_ONLY("^", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitwiseXor, $1, $3, @2); + } ; inclusive_or_expression : exclusive_or_expression { $$ = $1; } + | inclusive_or_expression VERTICAL_BAR exclusive_or_expression { + ES3_ONLY("|", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitwiseOr, $1, $3, @2); + } ; logical_and_expression : inclusive_or_expression { $$ = $1; } | logical_and_expression AND_OP inclusive_or_expression { - $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "&&", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLogicalAnd, $1, $3, @2); } ; logical_xor_expression : logical_and_expression { $$ = $1; } | logical_xor_expression XOR_OP logical_and_expression { - $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "^^", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLogicalXor, $1, $3, @2); } ; logical_or_expression : logical_xor_expression { $$ = $1; } | logical_or_expression OR_OP logical_xor_expression { - $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "||", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLogicalOr, $1, $3, @2); } ; @@ -727,12 +537,7 @@ assignment_expression | unary_expression assignment_operator assignment_expression { if (context->lValueErrorCheck(@2, "assign", $1)) context->recover(); - $$ = context->intermediate.addAssign($2.op, $1, $3, @2); - if ($$ == 0) { - context->assignError(@2, "assign", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addAssign($2.op, $1, $3, @2); } ; @@ -740,8 +545,32 @@ assignment_operator : EQUAL { $$.op = EOpAssign; } | MUL_ASSIGN { $$.op = EOpMulAssign; } | DIV_ASSIGN { $$.op = EOpDivAssign; } + | MOD_ASSIGN { + ES3_ONLY("%=", @$, "integer modulus operator"); + $$.op = EOpIModAssign; + } | ADD_ASSIGN { $$.op = EOpAddAssign; } | SUB_ASSIGN { $$.op = EOpSubAssign; } + | LEFT_ASSIGN { + ES3_ONLY("<<=", @$, "bit-wise operator"); + $$.op = EOpBitShiftLeftAssign; + } + | RIGHT_ASSIGN { + ES3_ONLY(">>=", @$, "bit-wise operator"); + $$.op = EOpBitShiftRightAssign; + } + | AND_ASSIGN { + ES3_ONLY("&=", @$, "bit-wise operator"); + $$.op = EOpBitwiseAndAssign; + } + | XOR_ASSIGN { + ES3_ONLY("^=", @$, "bit-wise operator"); + $$.op = EOpBitwiseXorAssign; + } + | OR_ASSIGN { + ES3_ONLY("|=", @$, "bit-wise operator"); + $$.op = EOpBitwiseOrAssign; + } ; expression @@ -877,7 +706,7 @@ function_prototype { // Insert the unmangled name to detect potential future redefinition as a variable. TFunction *function = new TFunction(NewPoolTString($1->getName().c_str()), $1->getReturnType()); - context->symbolTable.getOuterLevel()->insert(function); + context->symbolTable.getOuterLevel()->insertUnmangled(function); } // @@ -1599,12 +1428,14 @@ statement | simple_statement { $$ = $1; } ; -// Grammar Note: No labeled statements; 'goto' is not supported. +// Grammar Note: Labeled statements for SWITCH only; 'goto' is not supported. simple_statement : declaration_statement { $$ = $1; } | expression_statement { $$ = $1; } | selection_statement { $$ = $1; } + | switch_statement { $$ = $1; } + | case_label { $$ = $1; } | iteration_statement { $$ = $1; } | jump_statement { $$ = $1; } ; @@ -1677,7 +1508,21 @@ selection_rest_statement } ; -// Grammar Note: No 'switch'. Switch statements not supported. +switch_statement + : SWITCH LEFT_PAREN expression RIGHT_PAREN { ++context->mSwitchNestingLevel; } compound_statement { + $$ = context->addSwitch($3, $6, @1); + --context->mSwitchNestingLevel; + } + ; + +case_label + : CASE constant_expression COLON { + $$ = context->addCase($2, @1); + } + | DEFAULT COLON { + $$ = context->addDefault(@1); + } + ; condition // In 1996 c++ draft, conditions can include single declarations @@ -1703,22 +1548,22 @@ condition ; iteration_statement - : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { + : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { context->symbolTable.pop(); $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1); - --context->loopNestingLevel; + --context->mLoopNestingLevel; } - | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { + | DO { ++context->mLoopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { if (context->boolErrorCheck(@8, $6)) context->recover(); $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4); - --context->loopNestingLevel; + --context->mLoopNestingLevel; } - | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { + | FOR LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { context->symbolTable.pop(); $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast($5.node1), reinterpret_cast($5.node2), $7, @1); - --context->loopNestingLevel; + --context->mLoopNestingLevel; } ; @@ -1753,40 +1598,20 @@ for_rest_statement jump_statement : CONTINUE SEMICOLON { - if (context->loopNestingLevel <= 0) { - context->error(@1, "continue statement only allowed in loops", ""); - context->recover(); - } - $$ = context->intermediate.addBranch(EOpContinue, @1); + $$ = context->addBranch(EOpContinue, @1); } | BREAK SEMICOLON { - if (context->loopNestingLevel <= 0) { - context->error(@1, "break statement only allowed in loops", ""); - context->recover(); - } - $$ = context->intermediate.addBranch(EOpBreak, @1); + $$ = context->addBranch(EOpBreak, @1); } | RETURN SEMICOLON { - $$ = context->intermediate.addBranch(EOpReturn, @1); - if (context->currentFunctionType->getBasicType() != EbtVoid) { - context->error(@1, "non-void function must return a value", "return"); - context->recover(); - } + $$ = context->addBranch(EOpReturn, @1); } | RETURN expression SEMICOLON { - $$ = context->intermediate.addBranch(EOpReturn, $2, @1); - context->functionReturnsValue = true; - if (context->currentFunctionType->getBasicType() == EbtVoid) { - context->error(@1, "void function cannot return a value", "return"); - context->recover(); - } else if (*(context->currentFunctionType) != $2->getType()) { - context->error(@1, "function return is not matching type:", "return"); - context->recover(); - } + $$ = context->addBranch(EOpReturn, $2, @1); } | DISCARD SEMICOLON { FRAG_ONLY("discard", @1); - $$ = context->intermediate.addBranch(EOpKill, @1); + $$ = context->addBranch(EOpKill, @1); } ; @@ -1857,7 +1682,7 @@ function_definition // Remember the return type for later checking for RETURN statements. // context->currentFunctionType = &(prevDec->getReturnType()); - context->functionReturnsValue = false; + context->mFunctionReturnsValue = false; // // Insert parameters into the symbol table. @@ -1896,12 +1721,12 @@ function_definition } context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1); $1.intermAggregate = paramNodes; - context->loopNestingLevel = 0; + context->mLoopNestingLevel = 0; } compound_statement_no_new_scope { //?? Check that all paths return a value if return type != void ? // May be best done as post process phase on intermediate code - if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) { + if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->mFunctionReturnsValue) { context->error(@1, "function does not return a value:", "", $1.function->getName().c_str()); context->recover(); } @@ -1923,5 +1748,5 @@ function_definition %% int glslang_parse(TParseContext* context) { - return yyparse(context); + return yyparse(context, context->scanner); } diff --git a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp index 00780f0454..07c50f0ce5 100644 --- a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp +++ b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp @@ -131,6 +131,25 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) case EOpDivAssign: out << "divide second child into first child"; break; + case EOpIModAssign: + out << "modulo second child into first child"; + break; + case EOpBitShiftLeftAssign: + out << "bit-wise shift first child left by second child"; + break; + case EOpBitShiftRightAssign: + out << "bit-wise shift first child right by second child"; + break; + case EOpBitwiseAndAssign: + out << "bit-wise and second child into first child"; + break; + case EOpBitwiseXorAssign: + out << "bit-wise xor second child into first child"; + break; + case EOpBitwiseOrAssign: + out << "bit-wise or second child into first child"; + break; + case EOpIndexDirect: out << "direct index"; break; @@ -159,6 +178,25 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) case EOpDiv: out << "divide"; break; + case EOpIMod: + out << "modulo"; + break; + case EOpBitShiftLeft: + out << "bit-wise shift left"; + break; + case EOpBitShiftRight: + out << "bit-wise shift right"; + break; + case EOpBitwiseAnd: + out << "bit-wise and"; + break; + case EOpBitwiseXor: + out << "bit-wise xor"; + break; + case EOpBitwiseOr: + out << "bit-wise or"; + break; + case EOpEqual: out << "Compare Equal"; break; @@ -211,6 +249,36 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) out << "\n"; + // Special handling for direct indexes. Because constant + // unions are not aware they are struct indexes, treat them + // here where we have that contextual knowledge. + if (node->getOp() == EOpIndexDirectStruct || + node->getOp() == EOpIndexDirectInterfaceBlock) + { + mDepth++; + node->getLeft()->traverse(this); + mDepth--; + + TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion(); + ASSERT(intermConstantUnion); + + OutputTreeText(out, intermConstantUnion, mDepth + 1); + + // The following code finds the field name from the constant union + const ConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer(); + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); + ASSERT(structure || interfaceBlock); + + const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields(); + + const TField *field = fields[constantUnion->getIConst()]; + + out << constantUnion->getIConst() << " (field '" << field->name() << "')"; + + return false; + } + return true; } @@ -226,6 +294,7 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) case EOpPositive: out << "Positive sign"; break; case EOpVectorLogicalNot: case EOpLogicalNot: out << "Negate conditional"; break; + case EOpBitwiseNot: out << "bit-wise not"; break; case EOpPostIncrement: out << "Post-Increment"; break; case EOpPostDecrement: out << "Post-Decrement"; break; @@ -241,6 +310,13 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) case EOpAcos: out << "arc cosine"; break; case EOpAtan: out << "arc tangent"; break; + case EOpSinh: out << "hyperbolic sine"; break; + case EOpCosh: out << "hyperbolic cosine"; break; + case EOpTanh: out << "hyperbolic tangent"; break; + case EOpAsinh: out << "arc hyperbolic sine"; break; + case EOpAcosh: out << "arc hyperbolic cosine"; break; + case EOpAtanh: out << "arc hyperbolic tangent"; break; + case EOpExp: out << "exp"; break; case EOpLog: out << "log"; break; case EOpExp2: out << "exp2"; break; @@ -251,8 +327,26 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) case EOpAbs: out << "Absolute value"; break; case EOpSign: out << "Sign"; break; case EOpFloor: out << "Floor"; break; + case EOpTrunc: out << "Truncate"; break; + case EOpRound: out << "Round"; break; + case EOpRoundEven: out << "Round half even"; break; case EOpCeil: out << "Ceiling"; break; case EOpFract: out << "Fraction"; break; + case EOpIsNan: out << "Is not a number"; break; + case EOpIsInf: out << "Is infinity"; break; + + case EOpFloatBitsToInt: out << "float bits to int"; break; + case EOpFloatBitsToUint: out << "float bits to uint"; break; + case EOpIntBitsToFloat: out << "int bits to float"; break; + case EOpUintBitsToFloat: out << "uint bits to float"; break; + + case EOpPackSnorm2x16: out << "pack Snorm 2x16"; break; + case EOpPackUnorm2x16: out << "pack Unorm 2x16"; break; + case EOpPackHalf2x16: out << "pack half 2x16"; break; + + case EOpUnpackSnorm2x16: out << "unpack Snorm 2x16"; break; + case EOpUnpackUnorm2x16: out << "unpack Unorm 2x16"; break; + case EOpUnpackHalf2x16: out << "unpack half 2x16"; break; case EOpLength: out << "length"; break; case EOpNormalize: out << "normalize"; break; @@ -260,6 +354,10 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) // case EOpDPdy: out << "dPdy"; break; // case EOpFwidth: out << "fwidth"; break; + case EOpDeterminant: out << "determinant"; break; + case EOpTranspose: out << "transpose"; break; + case EOpInverse: out << "inverse"; break; + case EOpAny: out << "any"; break; case EOpAll: out << "all"; break; @@ -326,6 +424,7 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) case EOpVectorNotEqual: out << "NotEqual"; break; case EOpMod: out << "mod"; break; + case EOpModf: out << "modf"; break; case EOpPow: out << "pow"; break; case EOpAtan: out << "arc tangent"; break; @@ -345,6 +444,8 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) case EOpRefract: out << "refract"; break; case EOpMul: out << "component-wise multiply"; break; + case EOpOuterProduct: out << "outer product"; break; + case EOpDeclaration: out << "Declaration: "; break; case EOpInvariantDeclaration: out << "Invariant Declaration: "; break; @@ -518,14 +619,13 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node) // // This function is the one to call externally to start the traversal. // Individual functions can be initialized to 0 to skip processing of that -// type of node. It's children will still be processed. +// type of node. Its children will still be processed. // -void TIntermediate::outputTree(TIntermNode *root) +void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink) { - if (root == NULL) - return; + TOutputTraverser it(infoSink); - TOutputTraverser it(mInfoSink.info); + ASSERT(root); root->traverse(&it); } diff --git a/src/3rdparty/angle/src/compiler/translator/intermediate.h b/src/3rdparty/angle/src/compiler/translator/intermediate.h deleted file mode 100644 index 3b7e7bd802..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/intermediate.h +++ /dev/null @@ -1,67 +0,0 @@ -// -// 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_LOCAL_INTERMEDIATE_H_ -#define COMPILER_TRANSLATOR_LOCAL_INTERMEDIATE_H_ - -#include "compiler/translator/IntermNode.h" - -struct TVectorFields -{ - int offsets[4]; - int num; -}; - -// -// Set of helper functions to help parse and build the tree. -// -class TInfoSink; -class TIntermediate -{ - public: - POOL_ALLOCATOR_NEW_DELETE(); - 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 // COMPILER_TRANSLATOR_LOCAL_INTERMEDIATE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/length_limits.h b/src/3rdparty/angle/src/compiler/translator/length_limits.h index df70ee5d84..88634381fa 100644 --- a/src/3rdparty/angle/src/compiler/translator/length_limits.h +++ b/src/3rdparty/angle/src/compiler/translator/length_limits.h @@ -8,8 +8,8 @@ // length_limits.h // -#if !defined(__LENGTH_LIMITS_H) -#define __LENGTH_LIMITS_H 1 +#ifndef COMPILER_TRANSLATOR_LENGTHLIMITS_H_ +#define COMPILER_TRANSLATOR_LENGTHLIMITS_H_ #include "GLSLANG/ShaderLang.h" @@ -18,4 +18,4 @@ size_t GetGlobalMaxTokenSize(ShShaderSpec spec); -#endif // !(defined(__LENGTH_LIMITS_H) +#endif // COMPILER_TRANSLATOR_LENGTHLIMITS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h index 80d5f7fa7f..b8c7e82956 100644 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h +++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h @@ -4,35 +4,36 @@ // found in the LICENSE file. // -#ifndef COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ -#define COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ +#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ +#define COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ #include "compiler/translator/IntermNode.h" #include "compiler/translator/depgraph/DependencyGraph.h" class TInfoSinkBase; -class RestrictFragmentShaderTiming : TDependencyGraphTraverser { -public: - RestrictFragmentShaderTiming(TInfoSinkBase& sink); - void enforceRestrictions(const TDependencyGraph& graph); +class RestrictFragmentShaderTiming : TDependencyGraphTraverser +{ + public: + RestrictFragmentShaderTiming(TInfoSinkBase &sink); + void enforceRestrictions(const TDependencyGraph &graph); int numErrors() const { return mNumErrors; } - virtual void visitArgument(TGraphArgument* parameter); - virtual void visitSelection(TGraphSelection* selection); - virtual void visitLoop(TGraphLoop* loop); - virtual void visitLogicalOp(TGraphLogicalOp* logicalOp); + void visitArgument(TGraphArgument *parameter) override; + void visitSelection(TGraphSelection *selection) override; + void visitLoop(TGraphLoop *loop) override; + void visitLogicalOp(TGraphLogicalOp *logicalOp) override; -private: - void beginError(const TIntermNode* node); - void validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph); - bool isSamplingOp(const TIntermAggregate* intermFunctionCall) const; + private: + void beginError(const TIntermNode *node); + void validateUserDefinedFunctionCallUsage(const TDependencyGraph &graph); + bool isSamplingOp(const TIntermAggregate *intermFunctionCall) const; - TInfoSinkBase& mSink; + TInfoSinkBase &mSink; int mNumErrors; typedef std::set StringSet; StringSet mSamplingOps; }; -#endif // COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ +#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h index a6263567b4..74bfd0b5c2 100644 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h +++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ -#define COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ +#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ +#define COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ #include "compiler/translator/IntermNode.h" #include "compiler/translator/InfoSink.h" @@ -28,4 +28,4 @@ private: int mNumErrors; }; -#endif // COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ +#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/util.cpp b/src/3rdparty/angle/src/compiler/translator/util.cpp index 8cc06a658a..42a995ee6f 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.cpp +++ b/src/3rdparty/angle/src/compiler/translator/util.cpp @@ -307,7 +307,7 @@ void GetVariableTraverser::setTypeSpecificInfo( break; case EvqVaryingIn: case EvqVaryingOut: - if (mSymbolTable.isVaryingInvariant(name)) + if (mSymbolTable.isVaryingInvariant(std::string(name.c_str()))) { variable->isInvariant = true; } diff --git a/src/3rdparty/angle/src/compiler/translator/util.h b/src/3rdparty/angle/src/compiler/translator/util.h index fb5308759e..68bae66168 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.h +++ b/src/3rdparty/angle/src/compiler/translator/util.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_UTIL_H -#define COMPILER_UTIL_H +#ifndef COMPILER_TRANSLATOR_UTIL_H_ +#define COMPILER_TRANSLATOR_UTIL_H_ #include @@ -37,7 +37,7 @@ bool IsVarying(TQualifier qualifier); InterpolationType GetInterpolationType(TQualifier qualifier); TString ArrayString(const TType &type); -class GetVariableTraverser +class GetVariableTraverser : angle::NonCopyable { public: GetVariableTraverser(const TSymbolTable &symbolTable); @@ -57,10 +57,8 @@ class GetVariableTraverser const TType &type, const TString &name, VarT *variable) {} const TSymbolTable &mSymbolTable; - - DISALLOW_COPY_AND_ASSIGN(GetVariableTraverser); }; } -#endif // COMPILER_UTIL_H +#endif // COMPILER_TRANSLATOR_UTIL_H_ -- cgit v1.2.3